[pypy-commit] pypy default: Support PyHeapTypeObject in cpyext;

amauryfa noreply at buildbot.pypy.org
Tue Sep 27 23:14:34 CEST 2011


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: 
Changeset: r47643:2017ff82bfd2
Date: 2011-09-21 00:19 +0200
http://bitbucket.org/pypy/pypy/changeset/2017ff82bfd2/

Log:	Support PyHeapTypeObject in cpyext; Most pypy types now use this
	structure as well.

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -57,6 +57,9 @@
         compile_extra=['-DPy_BUILD_CORE'],
         )
 
+class CConfig2:
+    _compilation_info_ = CConfig._compilation_info_
+
 class CConfig_constants:
     _compilation_info_ = CConfig._compilation_info_
 
@@ -300,9 +303,13 @@
         return unwrapper_raise # used in 'normal' RPython code.
     return decorate
 
-def cpython_struct(name, fields, forward=None):
+def cpython_struct(name, fields, forward=None, level=1):
     configname = name.replace(' ', '__')
-    setattr(CConfig, configname, rffi_platform.Struct(name, fields))
+    if level == 1:
+        config = CConfig
+    else:
+        config = CConfig2
+    setattr(config, configname, rffi_platform.Struct(name, fields))
     if forward is None:
         forward = lltype.ForwardReference()
     TYPES[configname] = forward
@@ -445,9 +452,10 @@
 #              'int*': rffi.INTP}
 
 def configure_types():
-    for name, TYPE in rffi_platform.configure(CConfig).iteritems():
-        if name in TYPES:
-            TYPES[name].become(TYPE)
+    for config in (CConfig, CConfig2):
+        for name, TYPE in rffi_platform.configure(config).iteritems():
+            if name in TYPES:
+                TYPES[name].become(TYPE)
 
 def build_type_checkers(type_name, cls=None):
     """
diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -321,6 +321,15 @@
 
 } PyTypeObject;
 
+typedef struct {
+    PyTypeObject ht_type;
+    PyNumberMethods as_number;
+    PyMappingMethods as_mapping;
+    PySequenceMethods as_sequence;
+    PyBufferProcs as_buffer;
+    PyObject *ht_name, *ht_slots;
+} PyHeapTypeObject;
+
 /* Flag bits for printing: */
 #define Py_PRINT_RAW	1	/* No string quotes etc. */
 
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -19,13 +19,42 @@
     basestruct = PyObject.TO
 
     def get_dealloc(self, space):
-        raise NotImplementedError
+        from pypy.module.cpyext.typeobject import subtype_dealloc
+        return llhelper(
+            subtype_dealloc.api_func.functype,
+            subtype_dealloc.api_func.get_wrapper(space))
+
     def allocate(self, space, w_type, itemcount=0):
-        raise NotImplementedError
+        # similar to PyType_GenericAlloc?
+        # except that it's not related to any pypy object.
+
+        pytype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_type))
+        # Don't increase refcount for non-heaptypes
+        if pytype:
+            flags = rffi.cast(lltype.Signed, pytype.c_tp_flags)
+            if not flags & Py_TPFLAGS_HEAPTYPE:
+                Py_DecRef(space, w_type)
+
+        if pytype:
+            size = pytype.c_tp_basicsize
+        else:
+            size = rffi.sizeof(self.basestruct)
+        if itemcount:
+            size += itemcount * pytype.c_tp_itemsize
+        buf = lltype.malloc(rffi.VOIDP.TO, size,
+                            flavor='raw', zero=True)
+        pyobj = rffi.cast(PyObject, buf)
+        pyobj.c_ob_refcnt = 1
+        pyobj.c_ob_type = pytype
+        return pyobj
+
     def attach(self, space, pyobj, w_obj):
-        raise NotImplementedError
+        pass
+
     def realize(self, space, ref):
-        raise NotImplementedError
+        # For most types, a reference cannot exist without
+        # a real interpreter object
+        raise InvalidPointerException(str(ref))
 
 typedescr_cache = {}
 
@@ -40,6 +69,7 @@
     """
 
     tp_basestruct = kw.pop('basestruct', PyObject.TO)
+    tp_alloc      = kw.pop('alloc', None)
     tp_attach     = kw.pop('attach', None)
     tp_realize    = kw.pop('realize', None)
     tp_dealloc    = kw.pop('dealloc', None)
@@ -49,58 +79,24 @@
 
     class CpyTypedescr(BaseCpyTypedescr):
         basestruct = tp_basestruct
-        realize = tp_realize
 
-        def get_dealloc(self, space):
-            if tp_dealloc:
+        if tp_alloc:
+            def allocate(self, space, w_type, itemcount=0):
+                return tp_alloc(space, w_type)
+
+        if tp_dealloc:
+            def get_dealloc(self, space):
                 return llhelper(
                     tp_dealloc.api_func.functype,
                     tp_dealloc.api_func.get_wrapper(space))
-            else:
-                from pypy.module.cpyext.typeobject import subtype_dealloc
-                return llhelper(
-                    subtype_dealloc.api_func.functype,
-                    subtype_dealloc.api_func.get_wrapper(space))
-
-        def allocate(self, space, w_type, itemcount=0):
-            # similar to PyType_GenericAlloc?
-            # except that it's not related to any pypy object.
-
-            pytype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_type))
-            # Don't increase refcount for non-heaptypes
-            if pytype:
-                flags = rffi.cast(lltype.Signed, pytype.c_tp_flags)
-                if not flags & Py_TPFLAGS_HEAPTYPE:
-                    Py_DecRef(space, w_type)
-
-            if pytype:
-                size = pytype.c_tp_basicsize
-            else:
-                size = rffi.sizeof(tp_basestruct)
-            if itemcount:
-                size += itemcount * pytype.c_tp_itemsize
-            buf = lltype.malloc(rffi.VOIDP.TO, size,
-                                flavor='raw', zero=True)
-            pyobj = rffi.cast(PyObject, buf)
-            pyobj.c_ob_refcnt = 1
-            pyobj.c_ob_type = pytype
-            return pyobj
 
         if tp_attach:
             def attach(self, space, pyobj, w_obj):
                 tp_attach(space, pyobj, w_obj)
-        else:
-            def attach(self, space, pyobj, w_obj):
-                pass
 
         if tp_realize:
             def realize(self, space, ref):
                 return tp_realize(space, ref)
-        else:
-            def realize(self, space, ref):
-                # For most types, a reference cannot exist without
-                # a real interpreter object
-                raise InvalidPointerException(str(ref))
     if typedef:
         CpyTypedescr.__name__ = "CpyTypedescr_%s" % (typedef.name,)
 
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -268,6 +268,21 @@
         assert type(obj) is foo.Custom
         assert type(foo.Custom) is foo.MetaType
 
+    def test_heaptype(self):
+        module = self.import_extension('foo', [
+           ("name_by_heaptype", "METH_O",
+            '''
+                 PyHeapTypeObject *heaptype = (PyHeapTypeObject *)args;
+                 Py_INCREF(heaptype->ht_name);
+                 return heaptype->ht_name;
+             '''
+             )
+            ])
+        class C(object):
+            pass
+        assert module.name_by_heaptype(C) == "C"
+        
+
 class TestTypes(BaseApiTest):
     def test_type_attributes(self, space, api):
         w_class = space.appexec([], """():
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -11,7 +11,7 @@
     generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
     Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
     Py_TPFLAGS_HAVE_GETCHARBUFFER,
-    build_type_checkers)
+    build_type_checkers, PyObjectFields)
 from pypy.module.cpyext.pyobject import (
     PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
     track_reference, RefcountState, borrow_from)
@@ -25,7 +25,7 @@
 from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
 from pypy.module.cpyext.typeobjectdefs import (
     PyTypeObjectPtr, PyTypeObject, PyGetSetDef, PyMemberDef, newfunc,
-    PyNumberMethods, PySequenceMethods, PyBufferProcs)
+    PyNumberMethods, PyMappingMethods, PySequenceMethods, PyBufferProcs)
 from pypy.module.cpyext.slotdefs import (
     slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
 from pypy.interpreter.error import OperationError
@@ -39,6 +39,19 @@
 
 PyType_Check, PyType_CheckExact = build_type_checkers("Type", "w_type")
 
+PyHeapTypeObjectStruct = lltype.ForwardReference()
+PyHeapTypeObject = lltype.Ptr(PyHeapTypeObjectStruct)
+PyHeapTypeObjectFields = (
+    ("ht_type", PyTypeObject),
+    ("ht_name", PyObject),
+    ("as_number", PyNumberMethods),
+    ("as_mapping", PyMappingMethods),
+    ("as_sequence", PySequenceMethods),
+    ("as_buffer", PyBufferProcs),
+    )
+cpython_struct("PyHeapTypeObject", PyHeapTypeObjectFields, PyHeapTypeObjectStruct,
+               level=2)
+
 class W_GetSetPropertyEx(GetSetProperty):
     def __init__(self, getset, w_type):
         self.getset = getset
@@ -136,6 +149,8 @@
             assert len(slot_names) == 2
             struct = getattr(pto, slot_names[0])
             if not struct:
+                assert not space.config.translating
+                assert not pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE
                 if slot_names[0] == 'c_tp_as_number':
                     STRUCT_TYPE = PyNumberMethods
                 elif slot_names[0] == 'c_tp_as_sequence':
@@ -301,6 +316,7 @@
 
     make_typedescr(space.w_type.instancetypedef,
                    basestruct=PyTypeObject,
+                   alloc=type_alloc,
                    attach=type_attach,
                    realize=type_realize,
                    dealloc=type_dealloc)
@@ -319,11 +335,13 @@
     track_reference(space, lltype.nullptr(PyObject.TO), space.w_type)
     track_reference(space, lltype.nullptr(PyObject.TO), space.w_object)
     track_reference(space, lltype.nullptr(PyObject.TO), space.w_tuple)
+    track_reference(space, lltype.nullptr(PyObject.TO), space.w_str)
 
     # create the objects
     py_type = create_ref(space, space.w_type)
     py_object = create_ref(space, space.w_object)
     py_tuple = create_ref(space, space.w_tuple)
+    py_str = create_ref(space, space.w_str)
 
     # form cycles
     pto_type = rffi.cast(PyTypeObjectPtr, py_type)
@@ -340,10 +358,15 @@
     pto_object.c_tp_bases.c_ob_type = pto_tuple
     pto_tuple.c_tp_bases.c_ob_type = pto_tuple
 
+    for typ in (py_type, py_object, py_tuple, py_str):
+        heaptype = rffi.cast(PyHeapTypeObject, typ)
+        heaptype.c_ht_name.c_ob_type = pto_type
+
     # Restore the mapping
     track_reference(space, py_type, space.w_type, replace=True)
     track_reference(space, py_object, space.w_object, replace=True)
     track_reference(space, py_tuple, space.w_tuple, replace=True)
+    track_reference(space, py_str, space.w_str, replace=True)
 
 
 @cpython_api([PyObject], lltype.Void, external=False)
@@ -416,17 +439,34 @@
     Py_DecRef(space, obj_pto.c_tp_cache) # let's do it like cpython
     Py_DecRef(space, obj_pto.c_tp_dict)
     if obj_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
-        if obj_pto.c_tp_as_buffer:
-            lltype.free(obj_pto.c_tp_as_buffer, flavor='raw')
-        if obj_pto.c_tp_as_number:
-            lltype.free(obj_pto.c_tp_as_number, flavor='raw')
-        if obj_pto.c_tp_as_sequence:
-            lltype.free(obj_pto.c_tp_as_sequence, flavor='raw')
+        heaptype = rffi.cast(PyHeapTypeObject, obj)
+        Py_DecRef(space, heaptype.c_ht_name)
         Py_DecRef(space, base_pyo)
-        rffi.free_charp(obj_pto.c_tp_name)
         PyObject_dealloc(space, obj)
 
 
+def type_alloc(space, w_metatype):
+    size = rffi.sizeof(PyHeapTypeObject)
+    metatype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_metatype))
+    # Don't increase refcount for non-heaptypes
+    if metatype:
+        flags = rffi.cast(lltype.Signed, metatype.c_tp_flags)
+        if not flags & Py_TPFLAGS_HEAPTYPE:
+            Py_DecRef(space, w_metatype)
+
+    heaptype = lltype.malloc(PyHeapTypeObject.TO,
+                             flavor='raw', zero=True)
+    pto = heaptype.c_ht_type
+    pto.c_ob_refcnt = 1
+    pto.c_ob_type = metatype
+    pto.c_tp_flags |= Py_TPFLAGS_HEAPTYPE
+    pto.c_tp_as_number = heaptype.c_as_number
+    pto.c_tp_as_sequence = heaptype.c_as_sequence
+    pto.c_tp_as_mapping = heaptype.c_as_mapping
+    pto.c_tp_as_buffer = heaptype.c_as_buffer
+    
+    return rffi.cast(PyObject, heaptype)
+
 def type_attach(space, py_obj, w_type):
     """
     Fills a newly allocated PyTypeObject from an existing type.
@@ -445,12 +485,18 @@
     if space.is_w(w_type, space.w_str):
         setup_string_buffer_procs(space, pto)
 
-    pto.c_tp_flags |= Py_TPFLAGS_HEAPTYPE
     pto.c_tp_free = llhelper(PyObject_Del.api_func.functype,
             PyObject_Del.api_func.get_wrapper(space))
     pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype,
             PyType_GenericAlloc.api_func.get_wrapper(space))
-    pto.c_tp_name = rffi.str2charp(w_type.getname(space))
+    if pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
+        w_typename = space.getattr(w_type, space.wrap('__name__'))
+        heaptype = rffi.cast(PyHeapTypeObject, pto)
+        heaptype.c_ht_name = make_ref(space, w_typename)
+        from pypy.module.cpyext.stringobject import PyString_AsString
+        pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name)
+    else:
+        pto.c_tp_name = rffi.str2charp(w_type.getname(space))
     pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out
     pto.c_tp_itemsize = 0
     # uninitialized fields:


More information about the pypy-commit mailing list