[pypy-svn] r74378 - pypy/trunk/pypy/module/cpyext

afa at codespeak.net afa at codespeak.net
Wed May 5 14:09:30 CEST 2010


Author: afa
Date: Wed May  5 14:09:28 2010
New Revision: 74378

Modified:
   pypy/trunk/pypy/module/cpyext/stringobject.py
   pypy/trunk/pypy/module/cpyext/unicodeobject.py
Log:
Document, factorize, rename some variables and reorganize imports.


Modified: pypy/trunk/pypy/module/cpyext/stringobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/stringobject.py	(original)
+++ pypy/trunk/pypy/module/cpyext/stringobject.py	Wed May  5 14:09:28 2010
@@ -1,11 +1,53 @@
 from pypy.interpreter.error import OperationError
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
-    cpython_api, bootstrap_function, PyVarObjectFields, Py_ssize_t,
-    cpython_struct, PyObjectFields, ADDR, CONST_STRING, CANNOT_FAIL,
-    build_type_checkers, PyObjectP, PyTypeObjectPtr, generic_cpy_call)
-from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref, Py_DecRef, make_typedescr
-from pypy.module.cpyext.state import State
+    cpython_api, cpython_struct, bootstrap_function, build_type_checkers,
+    PyObjectFields, Py_ssize_t, CONST_STRING)
+from pypy.module.cpyext.pyobject import (
+    PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference,
+    make_typedescr, get_typedescr)
+
+##
+## Implementation of PyStringObject
+## ================================
+##
+## The problem
+## -----------
+##
+## PyString_AsString() must returns a (non-movable) pointer to the underlying
+## buffer, whereas pypy strings are movable.  C code may temporarily store
+## this address and use it, as long as it owns a reference to the PyObject.
+## There is no "release" function to specify that the pointer is not needed
+## any more.
+##
+## Also, the pointer may be used to fill the initial value of string. This is
+## valid only when the string was just allocated, and is not used elsewhere.
+##
+## Solution
+## --------
+##
+## PyStringObject contains two additional members: the size and a pointer to a
+## char buffer; it may be NULL.
+##
+## - A string allocated by pypy will be converted into a PyStringObject with a
+##   NULL buffer.  The first time PyString_AsString() is called, memory is
+##   allocated (with flavor='raw') and content is copied.
+##
+## - A string allocated with PyString_FromStringAndSize(NULL, size) will
+##   allocate a PyStringObject structure, and a buffer with the specified
+##   size, but the reference won't be stored in the global map; there is no
+##   corresponding object in pypy.  When from_ref() or Py_INCREF() is called,
+##   the pypy string is created, and added to the global map of tracked
+##   objects.  The buffer is then supposed to be immutable.
+##
+## - _PyString_Resize() works only on not-yet-pypy'd strings, and returns a
+##   similar object.
+##
+## - PyString_Size() doesn't need to force the object.
+##
+## - There could be an (expensive!) check in from_ref() that the buffer still
+##   corresponds to the pypy gc-managed string.
+##
 
 PyStringObjectStruct = lltype.ForwardReference()
 PyStringObject = lltype.Ptr(PyStringObjectStruct)
@@ -15,6 +57,7 @@
 
 @bootstrap_function
 def init_stringobject(space):
+    "Type description of PyStringObject"
     make_typedescr(space.w_str.instancetypedef,
                    basestruct=PyStringObject.TO,
                    attach=string_attach,
@@ -24,40 +67,53 @@
 PyString_Check, PyString_CheckExact = build_type_checkers("String", "w_str")
 
 def new_empty_str(space, length):
-    py_str = lltype.malloc(PyStringObject.TO, flavor='raw')
-    py_str.c_ob_refcnt = 1
-    
+    """
+    Allocatse a PyStringObject and its buffer, but without a corresponding
+    interpreter object.  The buffer may be mutated, until string_realize() is
+    called.
+    """
+    typedescr = get_typedescr(space.w_str.instancetypedef)
+    py_obj = typedescr.allocate(space, space.w_str)
+    py_str = rffi.cast(PyStringObject, py_obj)
+
     buflen = length + 1
+    py_str.c_size = length
     py_str.c_buffer = lltype.malloc(rffi.CCHARP.TO, buflen,
                                     flavor='raw', zero=True)
-    py_str.c_size = length
-    py_str.c_ob_type = rffi.cast(PyTypeObjectPtr, make_ref(space, space.w_str))
     return py_str
 
 def string_attach(space, py_obj, w_obj):
+    """
+    Fills a newly allocated PyStringObject with the given string object. The
+    buffer must not be modified.
+    """
     py_str = rffi.cast(PyStringObject, py_obj)
     py_str.c_size = len(space.str_w(w_obj))
     py_str.c_buffer = lltype.nullptr(rffi.CCHARP.TO)
 
-def string_realize(space, ref):
-    state = space.fromcache(State)
-    ref = rffi.cast(PyStringObject, ref)
-    s = rffi.charpsize2str(ref.c_buffer, ref.c_size)
-    ref = rffi.cast(PyObject, ref)
-    w_str = space.wrap(s)
-    state.py_objects_w2r[w_str] = ref
-    ptr = rffi.cast(ADDR, ref)
-    state.py_objects_r2w[ptr] = w_str
-    return w_str
+def string_realize(space, py_obj):
+    """
+    Creates the string in the interpreter. The PyStringObject buffer must not
+    be modified after this call.
+    """
+    py_str = rffi.cast(PyStringObject, py_obj)
+    s = rffi.charpsize2str(py_str.c_buffer, py_str.c_size)
+    w_obj = space.wrap(s)
+    track_reference(space, py_obj, w_obj)
+    return w_obj
 
 @cpython_api([PyObject], lltype.Void, external=False)
 def string_dealloc(space, py_obj):
+    """Frees allocated PyStringObject resources.
+    """
     py_str = rffi.cast(PyStringObject, py_obj)
     if py_str.c_buffer:
         lltype.free(py_str.c_buffer, flavor="raw")
     from pypy.module.cpyext.object import PyObject_dealloc
     PyObject_dealloc(space, py_obj)
 
+#_______________________________________________________________________
+
 @cpython_api([CONST_STRING, Py_ssize_t], PyObject)
 def PyString_FromStringAndSize(space, char_p, length):
     if char_p:

Modified: pypy/trunk/pypy/module/cpyext/unicodeobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/unicodeobject.py	(original)
+++ pypy/trunk/pypy/module/cpyext/unicodeobject.py	Wed May  5 14:09:28 2010
@@ -3,15 +3,17 @@
 from pypy.module.unicodedata import unicodedb_4_1_0 as unicodedb
 from pypy.module.cpyext.api import (
     CANNOT_FAIL, Py_ssize_t, build_type_checkers, cpython_api,
-    bootstrap_function, generic_cpy_call, PyObjectFields,
-    cpython_struct, CONST_STRING, CONST_WSTRING)
+    bootstrap_function, PyObjectFields, cpython_struct, CONST_STRING,
+    CONST_WSTRING)
 from pypy.module.cpyext.pyerrors import PyErr_BadArgument
-from pypy.module.cpyext.pyobject import PyObject, from_ref, make_ref, Py_DecRef, make_typedescr
-from pypy.module.cpyext.stringobject import PyString_Check
+from pypy.module.cpyext.pyobject import PyObject, from_ref, make_typedescr
 from pypy.module.sys.interp_encoding import setdefaultencoding
 from pypy.objspace.std import unicodeobject, unicodetype
 import sys
 
+## See comment in stringobject.py.  PyUnicode_FromUnicode(NULL, size) is not
+## yet supported.
+
 PyUnicodeObjectStruct = lltype.ForwardReference()
 PyUnicodeObject = lltype.Ptr(PyUnicodeObjectStruct)
 PyUnicodeObjectFields = (PyObjectFields +
@@ -35,6 +37,7 @@
 Py_UNICODE = lltype.UniChar
 
 def unicode_attach(space, py_obj, w_obj):
+    "Fills a newly allocated PyUnicodeObject with a unicode string"
     py_unicode = rffi.cast(PyUnicodeObject, py_obj)
     py_unicode.c_size = len(space.unicode_w(w_obj))
     py_unicode.c_buffer = lltype.nullptr(rffi.CWCHARP.TO)
@@ -214,8 +217,7 @@
     if not wchar_p:
         raise NotImplementedError
     s = rffi.wcharpsize2unicode(wchar_p, length)
-    ptr = make_ref(space, space.wrap(s))
-    return ptr
+    return space.wrap(s)
 
 @cpython_api([CONST_WSTRING, Py_ssize_t], PyObject)
 def PyUnicode_FromWideChar(space, wchar_p, length):



More information about the Pypy-commit mailing list