[pypy-commit] pypy cpyext-gc-support-2: copy some code, rekill parts that I definitely want killed

arigo pypy.commits at gmail.com
Tue Jan 19 09:30:36 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: cpyext-gc-support-2
Changeset: r81855:e02a927b7f7a
Date: 2016-01-19 15:29 +0100
http://bitbucket.org/pypy/pypy/changeset/e02a927b7f7a/

Log:	copy some code, rekill parts that I definitely want killed

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
@@ -509,14 +509,16 @@
     return {"PyObject*": PyObject, "PyTypeObject*": PyTypeObjectPtr,
             "PyDateTime_CAPI*": lltype.Ptr(PyDateTime_CAPI)}[ctype]
 
+# Note: as a special case, "PyObject" is the pointer type in RPython,
+# corresponding to "PyObject *" in C.  We do that only for PyObject.
+# For example, "PyTypeObject" is the struct type even in RPython.
 PyTypeObject = lltype.ForwardReference()
 PyTypeObjectPtr = lltype.Ptr(PyTypeObject)
-# It is important that these PyObjects are allocated in a raw fashion
-# Thus we cannot save a forward pointer to the wrapped object
-# So we need a forward and backward mapping in our State instance
 PyObjectStruct = lltype.ForwardReference()
 PyObject = lltype.Ptr(PyObjectStruct)
-PyObjectFields = (("ob_refcnt", lltype.Signed), ("ob_type", PyTypeObjectPtr))
+PyObjectFields = (("ob_refcnt", lltype.Signed),
+                  ("ob_pypy_link", lltype.Signed),
+                  ("ob_type", PyTypeObjectPtr))
 PyVarObjectFields = PyObjectFields + (("ob_size", Py_ssize_t), )
 cpython_struct('PyObject', PyObjectFields, PyObjectStruct)
 PyVarObjectStruct = cpython_struct("PyVarObject", PyVarObjectFields)
@@ -827,6 +829,18 @@
 
     space.fromcache(State).install_dll(eci)
 
+    def dealloc_trigger():
+        print 'dealloc_trigger...'
+        while True:
+            ob = rawrefcount.next_dead(PyObject)
+            if not ob:
+                break
+            print ob
+            _Py_Dealloc(space, ob)
+        print 'dealloc_trigger DONE'
+        return "RETRY"
+    rawrefcount.init(dealloc_trigger)
+
     # populate static data
     for name, (typ, expr) in GLOBALS.iteritems():
         from pypy.module import cpyext
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
@@ -134,107 +134,6 @@
 #________________________________________________________
 # refcounted object support
 
-class RefcountState:
-    def __init__(self, space):
-        self.space = space
-        self.py_objects_w2r = {} # { w_obj -> raw PyObject }
-        self.py_objects_r2w = {} # { addr of raw PyObject -> w_obj }
-
-        self.lifeline_dict = RWeakKeyDictionary(W_Root, PyOLifeline)
-
-        self.borrow_mapping = {None: {}}
-        # { w_container -> { w_containee -> None } }
-        # the None entry manages references borrowed during a call to
-        # generic_cpy_call()
-
-        # For tests
-        self.non_heaptypes_w = []
-
-    def _cleanup_(self):
-        assert self.borrow_mapping == {None: {}}
-        self.py_objects_r2w.clear() # is not valid anymore after translation
-
-    def init_r2w_from_w2r(self):
-        """Rebuilds the dict py_objects_r2w on startup"""
-        for w_obj, obj in self.py_objects_w2r.items():
-            ptr = rffi.cast(ADDR, obj)
-            self.py_objects_r2w[ptr] = w_obj
-
-    def print_refcounts(self):
-        print "REFCOUNTS"
-        for w_obj, obj in self.py_objects_w2r.items():
-            print "%r: %i" % (w_obj, obj.c_ob_refcnt)
-
-    def get_from_lifeline(self, w_obj):
-        lifeline = self.lifeline_dict.get(w_obj)
-        if lifeline is not None: # make old PyObject ready for use in C code
-            py_obj = lifeline.pyo
-            assert py_obj.c_ob_refcnt == 0
-            return py_obj
-        else:
-            return lltype.nullptr(PyObject.TO)
-
-    def set_lifeline(self, w_obj, py_obj):
-        self.lifeline_dict.set(w_obj,
-                               PyOLifeline(self.space, py_obj))
-
-    def make_borrowed(self, w_container, w_borrowed):
-        """
-        Create a borrowed reference, which will live as long as the container
-        has a living reference (as a PyObject!)
-        """
-        ref = make_ref(self.space, w_borrowed)
-        obj_ptr = rffi.cast(ADDR, ref)
-
-        borrowees = self.borrow_mapping.setdefault(w_container, {})
-        if w_borrowed in borrowees:
-            Py_DecRef(self.space, w_borrowed) # cancel incref from make_ref()
-        else:
-            borrowees[w_borrowed] = None
-
-        return ref
-
-    def reset_borrowed_references(self):
-        "Used in tests"
-        for w_container, w_borrowed in self.borrow_mapping.items():
-            Py_DecRef(self.space, w_borrowed)
-        self.borrow_mapping = {None: {}}
-
-    def delete_borrower(self, w_obj):
-        """
-        Called when a potential container for borrowed references has lost its
-        last reference.  Removes the borrowed references it contains.
-        """
-        if w_obj in self.borrow_mapping: # move to lifeline __del__
-            for w_containee in self.borrow_mapping[w_obj]:
-                self.forget_borrowee(w_containee)
-            del self.borrow_mapping[w_obj]
-
-    def swap_borrow_container(self, container):
-        """switch the current default contained with the given one."""
-        if container is None:
-            old_container = self.borrow_mapping[None]
-            self.borrow_mapping[None] = {}
-            return old_container
-        else:
-            old_container = self.borrow_mapping[None]
-            self.borrow_mapping[None] = container
-            for w_containee in old_container:
-                self.forget_borrowee(w_containee)
-
-    def forget_borrowee(self, w_obj):
-        "De-register an object from the list of borrowed references"
-        ref = self.py_objects_w2r.get(w_obj, lltype.nullptr(PyObject.TO))
-        if not ref:
-            if DEBUG_REFCOUNT:
-                print >>sys.stderr, "Borrowed object is already gone!"
-            return
-
-        Py_DecRef(self.space, ref)
-
-class InvalidPointerException(Exception):
-    pass
-
 DEBUG_REFCOUNT = False
 
 def debug_refcount(*args, **kwargs):
@@ -382,68 +281,6 @@
     #      "'s type which is", rffi.charp2str(pto.c_tp_name)
     generic_cpy_call_dont_decref(space, pto.c_tp_dealloc, obj)
 
-#___________________________________________________________
-# Support for "lifelines"
-#
-# Object structure must stay alive even when not referenced
-# by any C code.
-
-class PyOLifeline(object):
-    def __init__(self, space, pyo):
-        self.pyo = pyo
-        self.space = space
-
-    def __del__(self):
-        if self.pyo:
-            assert self.pyo.c_ob_refcnt == 0
-            _Py_Dealloc(self.space, self.pyo)
-            self.pyo = lltype.nullptr(PyObject.TO)
-        # XXX handle borrowed objects here
-
-#___________________________________________________________
-# Support for borrowed references
-
-def make_borrowed_ref(space, w_container, w_borrowed):
-    """
-    Create a borrowed reference, which will live as long as the container
-    has a living reference (as a PyObject!)
-    """
-    if w_borrowed is None:
-        return lltype.nullptr(PyObject.TO)
-
-    state = space.fromcache(RefcountState)
-    return state.make_borrowed(w_container, w_borrowed)
-
-class Reference:
-    def __init__(self, pyobj):
-        assert not isinstance(pyobj, W_Root)
-        self.pyobj = pyobj
-
-    def get_ref(self, space):
-        return self.pyobj
-
-    def get_wrapped(self, space):
-        return from_ref(space, self.pyobj)
-
-class BorrowPair(Reference):
-    """
-    Delays the creation of a borrowed reference.
-    """
-    def __init__(self, w_container, w_borrowed):
-        self.w_container = w_container
-        self.w_borrowed = w_borrowed
-
-    def get_ref(self, space):
-        return make_borrowed_ref(space, self.w_container, self.w_borrowed)
-
-    def get_wrapped(self, space):
-        return self.w_borrowed
-
-def borrow_from(container, borrowed):
-    return BorrowPair(container, borrowed)
-
-#___________________________________________________________
-
 @cpython_api([rffi.VOIDP], lltype.Signed, error=CANNOT_FAIL)
 def _Py_HashPointer(space, ptr):
     return rffi.cast(lltype.Signed, ptr)
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
@@ -1,8 +1,11 @@
 from rpython.rlib.objectmodel import we_are_translated
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.interpreter.error import OperationError
+from pypy.interpreter.executioncontext import AsyncAction
 from rpython.rtyper.lltypesystem import lltype
+from rpython.rtyper.annlowlevel import llhelper
 from rpython.rlib.rdynload import DLLHANDLE
+from rpython.rlib import rawrefcount
 import sys
 
 class State:
@@ -11,6 +14,8 @@
         self.reset()
         self.programname = lltype.nullptr(rffi.CCHARP.TO)
         self.version = lltype.nullptr(rffi.CCHARP.TO)
+        pyobj_dealloc_action = PyObjDeallocAction(space)
+        self.dealloc_trigger = lambda: pyobj_dealloc_action.fire()
 
     def reset(self):
         from pypy.module.cpyext.modsupport import PyMethodDef
@@ -74,13 +79,15 @@
         "This function is called when the program really starts"
 
         from pypy.module.cpyext.typeobject import setup_new_method_def
-        from pypy.module.cpyext.pyobject import RefcountState
         from pypy.module.cpyext.api import INIT_FUNCTIONS
+        from pypy.module.cpyext.api import init_static_data_translated
+
+        if we_are_translated():
+            rawrefcount.init(llhelper(rawrefcount.RAWREFCOUNT_DEALLOC_TRIGGER,
+                                      self.dealloc_trigger))
+            init_static_data_translated(space)
 
         setup_new_method_def(space)
-        if we_are_translated():
-            refcountstate = space.fromcache(RefcountState)
-            refcountstate.init_r2w_from_w2r()
 
         for func in INIT_FUNCTIONS:
             func(space)
@@ -133,3 +140,17 @@
         w_dict = w_mod.getdict(space)
         w_copy = space.call_method(w_dict, 'copy')
         self.extensions[path] = w_copy
+
+
+class PyObjDeallocAction(AsyncAction):
+    """An action that invokes _Py_Dealloc() on the dying PyObjects.
+    """
+
+    def perform(self, executioncontext, frame):
+        from pypy.module.cpyext.pyobject import PyObject, _Py_Dealloc
+
+        while True:
+            py_obj = rawrefcount.next_dead(PyObject)
+            if not py_obj:
+                break
+            _Py_Dealloc(self.space, py_obj)


More information about the pypy-commit mailing list