[pypy-commit] pypy cpyext-gc-support: slowly-in-progress

arigo noreply at buildbot.pypy.org
Tue Oct 20 05:42:28 EDT 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cpyext-gc-support
Changeset: r80349:8294b8657c71
Date: 2015-10-20 11:42 +0200
http://bitbucket.org/pypy/pypy/changeset/8294b8657c71/

Log:	slowly-in-progress

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
@@ -681,9 +681,11 @@
             print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__
             print 'Either report a bug or consider not using this particular extension'
             if not we_are_translated():
+                tb = sys.exc_info()[2]
                 import traceback
                 traceback.print_exc()
-                print str(e)
+                if sys.stdout == sys.__stdout__:
+                    import pdb; pdb.post_mortem(tb)
                 # we can't do much here, since we're in ctypes, swallow
             else:
                 print str(e)
@@ -728,9 +730,9 @@
                                        compilation_info=eci, _nowrapper=True)
     def init_types(space):
         from pypy.module.cpyext.typeobject import py_type_ready
-        #py_type_ready(space, get_buffer_type()) ZZZ
-        #py_type_ready(space, get_cobject_type()) ZZZ
-        #py_type_ready(space, get_capsule_type()) ZZZ
+        py_type_ready(space, get_buffer_type())
+        py_type_ready(space, get_cobject_type())
+        py_type_ready(space, get_capsule_type())
     INIT_FUNCTIONS.append(init_types)
     from pypy.module.posix.interp_posix import add_fork_hook
     reinit_tls = rffi.llexternal('%sThread_ReInitTLS' % prefix, [], lltype.Void,
diff --git a/pypy/module/cpyext/intobject.py b/pypy/module/cpyext/intobject.py
--- a/pypy/module/cpyext/intobject.py
+++ b/pypy/module/cpyext/intobject.py
@@ -23,7 +23,7 @@
     setup_class_for_cpyext(W_AbstractIntObject,
                            basestruct=PyIntObject.TO,
                            fill_pyobj=int_fill_pyobj,
-                           realize=int_realize,
+                           fill_pypy=int_fill_pypy,
                            realize_subclass_of=W_IntObject)
 
 def int_fill_pyobj(space, w_obj, py_int):
@@ -33,8 +33,12 @@
     """
     py_int.c_ob_ival = space.int_w(w_obj)
 
-def int_realize(space, w_obj, py_obj):
-    intval = rffi.cast(lltype.Signed, rffi.cast(PyIntObject, py_obj).c_ob_ival)
+def int_fill_pypy(space, w_obj, py_obj):
+    """
+    Fills a W_IntObject from a PyIntObject.
+    """
+    py_int = rffi.cast(PyIntObject, py_obj)
+    intval = rffi.cast(lltype.Signed, py_int.c_ob_ival)
     W_IntObject.__init__(w_obj, intval)
 
 PyInt_Check, PyInt_CheckExact = build_type_checkers("Int")
diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -12,7 +12,7 @@
     METH_STATIC, METH_VARARGS, PyObject, PyObjectFields, bootstrap_function,
     build_type_checkers, cpython_api, cpython_struct, generic_cpy_call)
 from pypy.module.cpyext.pyobject import (
-    Py_DecRef, from_ref, make_ref, make_typedescr)
+    Py_DecRef, from_pyobj, make_ref, make_typedescr)
 
 PyCFunction_typedef = rffi.COpaquePtr(typedef='PyCFunction')
 PyCFunction = lltype.Ptr(lltype.FuncType([PyObject, PyObject], PyObject))
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
@@ -142,16 +142,18 @@
     """NOT_RPYTHON
 
     basestruct: The basic structure to allocate
-    alloc_pyobj: default create_pyobj calls this to get the PyObject
-    fill_pyobj: default create_pyobj calls this after attaching is done
-    realize   : Function called to create a pypy object from a PyObject
+    alloc_pyobj: function called to get the PyObject
+    fill_pyobj: called to fill the PyObject after attaching is done
+    alloc_pypy: function called to create a PyPy object from a PyObject
+    fill_pypy: called to fill the PyPy object after attaching is done
     dealloc   : a cpython_api(external=False), similar to PyObject_dealloc
     """
 
     tp_basestruct = kw.pop('basestruct', PyObject.TO)
     tp_alloc_pyobj  = kw.pop('alloc_pyobj', None)
     tp_fill_pyobj   = kw.pop('fill_pyobj', None)
-    tp_realize      = kw.pop('realize', None)
+    tp_alloc_pypy   = kw.pop('alloc_pypy', None)
+    tp_fill_pypy    = kw.pop('fill_pypy', None)
     force_create_pyobj  = kw.pop('force_create_pyobj', False)
     realize_subclass_of = kw.pop('realize_subclass_of', None)
     #tp_dealloc    = kw.pop('dealloc', None)
@@ -173,10 +175,10 @@
                 pass
         #
         def cpyext_create_pyobj(self, space):
-            py_obj, light = tp_alloc_pyobj(space, self)
+            py_obj, is_light = tp_alloc_pyobj(space, self)
             ob = rffi.cast(PyObject, py_obj)
             ob_type = get_c_ob_type(space, space.type(self))
-            init_link_pypy(self, ob, ob_type, light)
+            init_link_from_pypy(self, ob, ob_type, is_light)
             tp_fill_pyobj(space, self, py_obj)
             return ob
         W_Class.cpyext_create_pyobj = cpyext_create_pyobj
@@ -190,37 +192,56 @@
             keepalive_until_here(self)
         W_Class.cpyext_fill_prebuilt_pyobj = cpyext_fill_prebuilt_pyobj
 
-    if tp_realize or realize_subclass_of:
-        W_CPyExtPlaceHolder = get_cpyextplaceholder_subclass(
-            realize_subclass_of or W_Class)
-        if tp_realize:
-            tp_realize._always_inline_ = True
+    if tp_alloc_pyobj or tp_fill_pyobj or realize_subclass_of:
+        if realize_subclass_of is None:
+            realize_subclass_of = W_Class
+        assert 'typedef' in realize_subclass_of.__dict__, (
+            "no 'typedef' exactly on %s" % (realize_subclass_of,))
         #
-        def cpyext_realize(space, pyobj):
-            w_obj = W_CPyExtPlaceHolder(pyobj)
-            if tp_realize:
-                tp_realize(space, w_obj, pyobj)
+        if not tp_alloc_pypy:
+            W_CPyExtPlaceHolder = get_cpyextplaceholder_subclass(
+                realize_subclass_of)
+            def tp_alloc_pypy(space, pyobj):
+                w_obj = W_CPyExtPlaceHolder(pyobj)
+                return w_obj, True
+        tp_alloc_pypy._always_inline_ = True
+        #
+        if not tp_fill_pypy:
+            def tp_fill_pypy(space, w_obj, pyobj):
+                pass
+        #
+        def cpyext_create_pypy(space, pyobj):
+            w_obj, is_transient = tp_alloc_pypy(space, pyobj)
+            init_link_from_pyobj(w_obj, pyobj, is_transient)
+            tp_fill_pypy(space, w_obj, pyobj)
             return w_obj
         #
         typedef = realize_subclass_of.typedef
-        assert not hasattr(typedef, 'cpyext_realize')
-        typedef.cpyext_realize = cpyext_realize
+        assert 'cpyext_create_pypy' not in typedef.__dict__
+        typedef.cpyext_create_pypy = cpyext_create_pypy
 
     W_Class.cpyext_basestruct = tp_basestruct
 
 
-def init_link_pypy(w_obj, ob, ob_type, light):
-    if light:
+def init_link_from_pypy(w_obj, ob, ob_type, is_light):
+    if is_light:
         ob.c_ob_refcnt = rawrefcount.REFCNT_FROM_PYPY_LIGHT
     else:
         ob.c_ob_refcnt = rawrefcount.REFCNT_FROM_PYPY
-    ob.c_ob_pypy_link = 0
     ob.c_ob_type = ob_type
     rawrefcount.create_link_pypy(w_obj, ob)
 
+def init_link_from_pyobj(w_obj, ob, is_transient):
+    if is_transient:
+        rawrefcount.create_link_pyobj(w_obj, ob)
+    else:
+        rawrefcount.create_link_pypy(w_obj, ob)
+    ob.c_ob_refcnt += rawrefcount.REFCNT_FROM_PYPY
+
 def setup_prebuilt_pyobj(w_obj, py_obj):
     assert lltype.typeOf(py_obj) == PyObject
-    init_link_pypy(w_obj, py_obj, lltype.nullptr(PyTypeObjectPtr.TO), False)
+    init_link_from_pypy(w_obj, py_obj, lltype.nullptr(PyTypeObjectPtr.TO),
+                        False)
     if isinstance(w_obj, W_TypeObject):
         w_obj.cpyext_c_type_object = rffi.cast(PyTypeObjectPtr, py_obj)
 
@@ -236,6 +257,9 @@
 def init_pyobject(space):
     setup_class_for_cpyext(W_Root, force_create_pyobj=True,
                            realize_subclass_of=W_ObjectObject)
+    # use this cpyext_create_pypy as the default for all other TypeDefs
+    from pypy.interpreter.typedef import TypeDef
+    TypeDef.cpyext_create_pypy = W_ObjectObject.typedef.cpyext_create_pypy
 
 
 #________________________________________________________
@@ -262,6 +286,8 @@
         def cpyext_as_pyobj(self, space):
             return self.cpyext_pyobj
 
+        # ZZZ getclass(), getweakref(), etc.?  like interpreter/typedef.py
+
     W_CPyExtPlaceHolder.__name__ = W_Class.__name__ + '_CPyExtPlaceHolder'
     W_Class._cpyextplaceholder_subclass = W_CPyExtPlaceHolder
     return W_CPyExtPlaceHolder
@@ -284,8 +310,8 @@
 W_TypeObject._cpyextplaceholder_subclass = W_TypeObject
 
 def _create_w_obj_from_pyobj(space, pyobj):
-    w_type = from_pyobj(pyobj.c_ob_type)
-    return w_type.instancetypedef.cpyext_realize(space, pyobj)
+    w_type = from_pyobj(space, pyobj.c_ob_type)
+    return w_type.instancetypedef.cpyext_create_pypy(space, pyobj)
 
 #________________________________________________________
 # refcounted object support
diff --git a/pypy/module/cpyext/state.py b/pypy/module/cpyext/state.py
--- a/pypy/module/cpyext/state.py
+++ b/pypy/module/cpyext/state.py
@@ -82,8 +82,8 @@
         if we_are_translated():
             refcountstate = space.fromcache(RefcountState)
             refcountstate.init_r2w_from_w2r()
+            rawrefcount.init(lambda ob: ZZZ)
 
-        rawrefcount.init(lambda ob: ZZZ)
         for func in INIT_FUNCTIONS:
             func(space)
             self.check_and_raise_exception()
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
@@ -1,7 +1,7 @@
 import os
 
 from rpython.rlib import jit
-from rpython.rlib.objectmodel import specialize
+from rpython.rlib.objectmodel import specialize, instantiate
 from rpython.rlib.rstring import rsplit
 from rpython.rtyper.annlowlevel import llhelper
 from rpython.rtyper.lltypesystem import rffi, lltype
@@ -280,34 +280,13 @@
         check_descr(space, w_self, self.w_type)
         PyMember_SetOne(space, w_self, self.member, w_value)
 
-class W_PyCTypeObject(W_TypeObject):
-    @jit.dont_look_inside
-    def __init__(self, space, pto):
-        bases_w = space.fixedview(from_ref(space, pto.c_tp_bases))
-        dict_w = {}
-
-        add_operators(space, dict_w, pto)
-        convert_method_defs(space, dict_w, pto.c_tp_methods, self)
-        convert_getset_defs(space, dict_w, pto.c_tp_getset, self)
-        convert_member_defs(space, dict_w, pto.c_tp_members, self)
-
-        name = rffi.charp2str(pto.c_tp_name)
-
-        W_TypeObject.__init__(self, space, name,
-            bases_w or [space.w_object], dict_w)
-        if not space.is_true(space.issubtype(self, space.w_type)):
-            self.flag_cpytype = True
-        self.flag_heaptype = False
-        if pto.c_tp_doc:
-            self.w_doc = space.wrap(rffi.charp2str(pto.c_tp_doc))
-
 @bootstrap_function
 def init_typeobject(space):
     setup_class_for_cpyext(W_TypeObject,
                            basestruct=PyTypeObject,
                            alloc_pyobj=type_alloc_pyobj,
-                           fill_pyobj=type_fill_pyobj)
-                   #realize=type_realize,
+                           fill_pyobj=type_fill_pyobj,
+                           alloc_pypy=type_alloc_pypy)
                    #dealloc=type_dealloc)
 
     # some types are difficult to create because of cycles.
@@ -482,6 +461,7 @@
 def type_alloc_pyobj(space, w_type):
     pto = lltype.malloc(PyTypeObject, flavor='raw', zero=True,
                         track_allocation=False)
+    pto.c_tp_flags |= Py_TPFLAGS_READYING
     return pto, False
 
 def type_fill_pyobj(space, w_type, pto):
@@ -489,6 +469,9 @@
     Fills a newly allocated PyTypeObject from an existing w_type.
     """
     from pypy.module.cpyext.object import PyObject_Del
+    from rpython.rlib import rawrefcount
+
+    assert w_type == rawrefcount.to_obj(W_Root, pto)
 
     assert isinstance(w_type, W_TypeObject)
     w_type.cpyext_c_type_object = pto
@@ -526,39 +509,99 @@
     w_base = best_base(space, w_type.bases_w)
     pto.c_tp_base = rffi.cast(PyTypeObjectPtr,
                               get_pyobj_and_xincref(space, w_base))
+    w_bases = space.newtuple(w_type.bases_w)
+    pto.c_tp_bases = get_pyobj_and_incref(space, w_bases)
 
-    finish_type_1(space, pto, w_type)
     finish_type_2(space, pto, w_type)
 
     #pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct)   ZZZ
+    pto.c_tp_basicsize = rffi.sizeof(PyObject.TO)         #   ZZZ
     if pto.c_tp_base:
         if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize:
             pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize
 
     update_all_slots(space, w_type, pto)
+    pto.c_tp_flags &= ~Py_TPFLAGS_READYING
     pto.c_tp_flags |= Py_TPFLAGS_READY
 
 def py_type_ready(space, pto):
-    if pto.c_tp_flags & Py_TPFLAGS_READY:
-        return
-    type_realize(space, rffi.cast(PyObject, pto))
+    if pto.c_tp_flags & Py_TPFLAGS_READY == 0:
+        # this builds the W_TypeObject, and in doing so makes sure the
+        # PyTypeObject is ready.
+        if not pto.c_ob_type:
+            typetype = get_pyobj_and_incref(space, space.w_type)
+            pto.c_ob_type = rffi.cast(PyTypeObjectPtr, typetype)
+        from_pyobj(space, pto)
+        assert pto.c_tp_flags & Py_TPFLAGS_READY
 
 @cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
 def PyType_Ready(space, pto):
     py_type_ready(space, pto)
     return 0
 
-def type_realize(space, py_obj):
-    ZZZ
+ at jit.dont_look_inside
+def type_alloc_pypy(space, py_obj):
     pto = rffi.cast(PyTypeObjectPtr, py_obj)
+    assert pto.c_tp_flags & Py_TPFLAGS_READY == 0
     assert pto.c_tp_flags & Py_TPFLAGS_READYING == 0
     pto.c_tp_flags |= Py_TPFLAGS_READYING
     try:
-        w_obj = _type_realize(space, py_obj)
+        w_type = _type_realize(space, pto)
     finally:
         pto.c_tp_flags &= ~Py_TPFLAGS_READYING
     pto.c_tp_flags |= Py_TPFLAGS_READY
-    return w_obj
+    return w_type, False
+
+def _type_realize(space, pto):
+    assert pto.c_ob_type
+    # ^^^ we can't reach this place if c_ob_type is still NULL
+
+    if not pto.c_tp_base:
+        base = get_pyobj_and_incref(space, space.w_object)
+        pto.c_tp_base = rffi.cast(PyTypeObjectPtr, base)
+    PyType_Ready(space, pto.c_tp_base)
+
+    if not pto.c_tp_bases:
+        w_bases = space.newtuple([from_pyobj(space, pto.c_tp_base)])
+        pto.c_tp_bases = get_pyobj_and_incref(space, w_bases)
+    else:
+        w_bases = from_pyobj(space, pto.c_tp_bases)
+
+    w_metatype = from_pyobj(space, pto.c_ob_type)
+    w_type = space.allocate_instance(W_TypeObject, w_metatype)
+
+    bases_w = space.fixedview(w_bases) or [space.w_object]
+    name = rffi.charp2str(pto.c_tp_name)
+    dict_w = {}
+
+    # best we can do about tp_dict: copy all its string keys into dict_w,
+    # and ignore any non-string key
+    if pto.c_tp_dict:
+        w_org_dict = from_pyobj(space, pto.c_tp_dict)
+        for w_key in space.unpackiterable(w_org_dict):
+            try:
+                key = space.str_w(w_key)
+                dict_w[key] = space.getitem(w_org_dict, w_key)
+            except OperationError, e:
+                if e.async(self):
+                    raise
+
+    add_operators(space, dict_w, pto)
+    convert_method_defs(space, dict_w, pto.c_tp_methods, w_type)
+    convert_getset_defs(space, dict_w, pto.c_tp_getset, w_type)
+    convert_member_defs(space, dict_w, pto.c_tp_members, w_type)
+
+    W_TypeObject.__init__(w_type, space, name, bases_w, dict_w)
+
+    if not space.is_true(space.issubtype(self, space.w_type)):
+        w_type.flag_cpytype = True
+    w_type.flag_heaptype = False
+    if pto.c_tp_doc:
+        w_type.w_doc = space.wrap(rffi.charp2str(pto.c_tp_doc))
+
+    finish_type_2(space, pto, w_type)
+    w_type.ready()
+    return w_type
 
 def solid_base(space, w_type):
     typedef = w_type.instancetypedef
@@ -584,58 +627,12 @@
     if not pto.c_tp_setattro:
         pto.c_tp_setattro = base.c_tp_setattro
 
-def _type_realize(space, py_obj):
-    """
-    Creates an interpreter type from a PyTypeObject structure.
-    """
-    # missing:
-    # inheriting tp_as_* slots
-    # unsupported:
-    # tp_mro, tp_subclasses
-    py_type = rffi.cast(PyTypeObjectPtr, py_obj)
-
-    if not py_type.c_tp_base:
-        base = get_pyobj_and_incref(space, space.w_object)
-        py_type.c_tp_base = rffi.cast(PyTypeObjectPtr, base)
-
-    finish_type_1(space, py_type)
-
-    w_metatype = from_ref(space, rffi.cast(PyObject, py_type.c_ob_type))
-
-    w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype)
-    track_reference(space, py_obj, w_obj)
-    w_obj.__init__(space, py_type)
-    w_obj.ready()
-
-    finish_type_2(space, py_type, w_obj)
-
-    state = space.fromcache(RefcountState)
-    state.non_heaptypes_w.append(w_obj)
-
-    return w_obj
-
-def finish_type_1(space, pto, w_type):
-    """
-    Sets up tp_bases, necessary before creating the interpreter type.
-    """
-    #ZZZ
-    #base = pto.c_tp_base
-    #base_pyo = rffi.cast(PyObject, pto.c_tp_base)
-    #if base and not base.c_tp_flags & Py_TPFLAGS_READY:
-    #    type_realize(space, base_pyo)
-    #if base and not pto.c_ob_type: # will be filled later
-    #    pto.c_ob_type = base.c_ob_type
-    assert pto.c_ob_type    # ZZZ
-    if not pto.c_tp_bases:
-        w_bases = space.newtuple(w_type.bases_w)
-        pto.c_tp_bases = get_pyobj_and_incref(space, w_bases)
-
-def finish_type_2(space, pto, w_obj):
+def finish_type_2(space, pto, w_type):
     """
     Sets up other attributes, when the interpreter type has been created.
     """
     if not pto.c_tp_mro:
-        pto.c_tp_mro = get_pyobj_and_incref(space, space.newtuple(w_obj.mro_w))
+        pto.c_tp_mro = get_pyobj_and_incref(space, space.newtuple(w_type.mro_w))
     base = pto.c_tp_base
     if base:
         inherit_special(space, pto, base)
@@ -648,11 +645,11 @@
             PyObject_GenericSetAttr.api_func.functype,
             PyObject_GenericSetAttr.api_func.get_wrapper(space))
 
-    if w_obj.is_cpytype():
-        xxxxxxxx
-        Py_DecRef(space, pto.c_tp_dict)
-        w_dict = w_obj.getdict(space)
-        pto.c_tp_dict = make_ref(space, w_dict)
+    w_dict = w_type.getdict(space)
+    old = pto.c_tp_dict
+    pto.c_tp_dict = get_pyobj_and_incref(space, w_dict)
+    if old:
+        Py_DecRef(old)
 
 @cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
 def PyType_IsSubtype(space, a, b):
diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py
--- a/rpython/rlib/rawrefcount.py
+++ b/rpython/rlib/rawrefcount.py
@@ -32,8 +32,9 @@
 
 def create_link_pypy(p, ob):
     "NOT_RPYTHON: a link where the PyPy object contains some or all the data"
+    #print 'create_link_pypy\n\t%s\n\t%s' % (p, ob)
     assert p not in _pypy2ob
-    assert not ob.c_ob_pypy_link
+    #assert not ob.c_ob_pypy_link
     ob.c_ob_pypy_link = _build_pypy_link(p)
     _pypy2ob[p] = ob
     _p_list.append(ob)
@@ -41,8 +42,9 @@
 def create_link_pyobj(p, ob):
     """NOT_RPYTHON: a link where the PyObject contains all the data.
        from_obj() will not work on this 'p'."""
+    #print 'create_link_pyobj\n\t%s\n\t%s' % (p, ob)
     assert p not in _pypy2ob
-    assert not ob.c_ob_pypy_link
+    #assert not ob.c_ob_pypy_link
     ob.c_ob_pypy_link = _build_pypy_link(p)
     _o_list.append(ob)
 


More information about the pypy-commit mailing list