[pypy-commit] pypy cpyext-gc-cycle: Started implementation for gc.garbage, adapted interface

stevie_92 pypy.commits at gmail.com
Fri Mar 1 16:10:36 EST 2019


Author: Stefan Beyer <home at sbeyer.at>
Branch: cpyext-gc-cycle
Changeset: r96198:77d74e85609f
Date: 2019-03-01 22:09 +0100
http://bitbucket.org/pypy/pypy/changeset/77d74e85609f/

Log:	Started implementation for gc.garbage, adapted interface

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
@@ -13,7 +13,6 @@
 # context.
 ExecutionContext.cpyext_operror = None
 
-
 class State:
     def __init__(self, space):
         self.space = space
@@ -80,8 +79,6 @@
                 from pypy.interpreter.baseobjspace import W_Root
                 from pypy.module.cpyext.pyobject import PyObject, decref, \
                     incref, cts, finalize, from_ref
-                w_list = space.getattr(space.builtin_modules['gc'],
-                                       space.newtext('garbage'))
                 print 'dealloc_trigger...'
                 while True:
                     ob = rawrefcount.next_dead(PyObject)
@@ -116,17 +113,23 @@
                     if adr_int == llmemory.cast_adr_to_int(
                             llmemory.cast_ptr_to_adr(head)):
                         rawrefcount.cyclic_garbage_remove()
+                w_list = space.newlist([])
                 while True:
                     w_obj = rawrefcount.next_garbage_pypy(W_Root)
                     if not py_obj:
                         break
                     w_list.append(w_obj)
+                last_py_obj = lltype.nullptr(PyObject.TO)
                 while True:
-                    w_pyobj = rawrefcount.next_garbage_pyobj(PyObject)
-                    if not py_obj:
+                    w_pyobj = rawrefcount.next_garbage_pyobj(PyObject,
+                                                             last_py_obj)
+                    if not w_pyobj:
                         break
                     w_obj = from_ref(space, w_pyobj)
                     w_list.append(w_obj)
+                    last_py_obj = w_pyobj
+                space.setattr(space.builtin_modules['gc'],
+                              space.newtext('garbage'), w_list)
                 print 'dealloc_trigger DONE'
                 return "RETRY"
             def tp_traverse(pyobj_ptr, callback, args):
@@ -292,9 +295,6 @@
     from pypy.module.cpyext.pyobject import (PyObject, incref, decref,
                                              finalize, from_ref)
 
-    w_list = space.getattr(space.builtin_modules['gc'],
-                           space.newtext('garbage'))
-
     while True:
         py_obj = rawrefcount.next_dead(PyObject)
         if not py_obj:
@@ -321,17 +321,22 @@
         if adr_int == llmemory.cast_adr_to_int(llmemory.cast_ptr_to_adr(head)):
             rawrefcount.cyclic_garbage_remove()
 
+    w_list = space.newlist([])
     while True:
         w_obj = rawrefcount.next_garbage_pypy(W_Root)
         if not py_obj:
             break
         w_list.append(w_obj)
+    last_py_obj = lltype.nullptr(PyObject.TO)
     while True:
-        w_pyobj = rawrefcount.next_garbage_pyobj(PyObject)
-        if not py_obj:
+        w_pyobj = rawrefcount.next_garbage_pyobj(PyObject, last_py_obj)
+        if not w_pyobj:
             break
         w_obj = from_ref(space, w_pyobj)
         w_list.append(w_obj)
+        last_py_obj = w_pyobj
+    space.setattr(space.builtin_modules['gc'], space.newtext('garbage'),
+                  w_list)
 
 class PyObjDeallocAction(executioncontext.AsyncAction):
     """An action that invokes _Py_Dealloc() on the dying PyObjects.
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -3063,6 +3063,16 @@
 
     rrc_enabled = False
 
+    # The default state. Here cyclic garbage with legacy finalizers is marked.
+    RAWREFCOUNT_STATE_DEFAULT = 0
+
+    # The state in which cyclic garbage with legacy finalizers is traced.
+    # Do not mark objects during this state, because we remove the flag
+    # during tracing and we do not want to trace those objects again. Also
+    # during this phase no new objects can be marked, as we are only building
+    # the list of cyclic garbage.
+    RAWREFCOUNT_STATE_GARBAGE = 1
+
     _ADDRARRAY = lltype.Array(llmemory.Address, hints={'nolength': True})
     PYOBJ_HDR = lltype.Struct('GCHdr_PyObject',
                               ('c_ob_refcnt', lltype.Signed),
@@ -3128,6 +3138,7 @@
             self.rrc_pyobj_as_gc = pyobj_as_gc
             self.rrc_finalizer_type = finalizer_type
             self.rrc_enabled = True
+            self.rrc_state = self.RAWREFCOUNT_STATE_DEFAULT
 
     def check_no_more_rawrefcount_state(self):
         "NOT_RPYTHON: for tests"
@@ -3218,21 +3229,24 @@
         next.c_gc_prev = gchdr
 
     def rawrefcount_next_garbage_pypy(self):
+        if self.rrc_state == self.RAWREFCOUNT_STATE_DEFAULT:
+            self.rrc_state = self.RAWREFCOUNT_STATE_GARBAGE
+
         # return the next pypy object which is only reachable from garbage
         # pyobjects, probably need two more colors for this. one for marking
         # so that they stay alive during sweep, one for marking, so they do not
         # get returned here again
-        return lltype.nullptr(llmemory.GCREF.TO)
-
-    def rawrefcount_next_garbage_pyobj(self):
+        result = lltype.nullptr(llmemory.GCREF.TO)
+
+        if result == lltype.nullptr(llmemory.GCREF.TO):
+            self.rrc_state = self.RAWREFCOUNT_STATE_DEFAULT
+        return result
+
+    def rawrefcount_next_garbage_pyobj(self, curr_pyobj):
         # implement st objects in this list still remain in the set of
         # all pyobjs, because references could still change and cause them
         # to live again. also keep in mind, that state will create references
         # to pyobjs in this list and might increment the refcount.
-
-        # use create_link_pyobj on the result to create gc objects for pyobjects
-        #p = W_Root(42)
-        #p.pyobj = ob
         return llmemory.NULL
 
 
diff --git a/rpython/memory/gc/test/test_rawrefcount.py b/rpython/memory/gc/test/test_rawrefcount.py
--- a/rpython/memory/gc/test/test_rawrefcount.py
+++ b/rpython/memory/gc/test/test_rawrefcount.py
@@ -627,12 +627,16 @@
                     self.gc.rawrefcount_cyclic_garbage_remove()
                     next_dead = self.gc.rawrefcount_cyclic_garbage_head()
 
-            next = self.gc.rawrefcount_next_garbage_pypy()
-            while next <> lltype.nullptr(llmemory.GCREF.TO):
-                garbage_pypy.append(next)
-            next = self.gc.rawrefcount_next_garbage_pyobj()
+            next_garbage = self.gc.rawrefcount_next_garbage_pypy()
+            while next_garbage <> lltype.nullptr(llmemory.GCREF.TO):
+                garbage_pypy.append(next_garbage)
+                next_garbage = self.gc.rawrefcount_next_garbage_pypy()
+            last_pyobj = llmemory.NULL
+            next = self.gc.rawrefcount_next_garbage_pyobj(last_pyobj)
             while next <> llmemory.NULL:
                 garbage_pyobj.append(next)
+                next = self.gc.rawrefcount_next_garbage_pyobj(last_pyobj)
+                last_pyobj = next
 
         # do a collection to find cyclic isolates and clean them, if there are
         # no finalizers
diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -522,7 +522,7 @@
                 GCClass.rawrefcount_next_garbage_pypy, [s_gc],
                 s_gcref, inline = True)
             self.rawrefcount_next_garbage_pyobj_ptr = getfn(
-                GCClass.rawrefcount_next_garbage_pyobj, [s_gc],
+                GCClass.rawrefcount_next_garbage_pyobj, [s_gc, SomeAddress()],
                 SomeAddress(), inline = True)
 
         if GCClass.can_usually_pin_objects:
@@ -1439,9 +1439,12 @@
                   resultvar=hop.spaceop.result)
 
     def gct_gc_rawrefcount_next_garbage_pyobj(self, hop):
+        [v_pyobject] = hop.spaceop.args
+        assert v_pyobject.concretetype == llmemory.Address
         assert hop.spaceop.result.concretetype == llmemory.Address
         hop.genop("direct_call",
-                  [self.rawrefcount_next_garbage_pyobj_ptr, self.c_const_gc],
+                  [self.rawrefcount_next_garbage_pyobj_ptr, self.c_const_gc,
+                   v_pyobject],
                   resultvar=hop.spaceop.result)
 
     def _set_into_gc_array_part(self, op):
diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py
--- a/rpython/rlib/rawrefcount.py
+++ b/rpython/rlib/rawrefcount.py
@@ -147,10 +147,10 @@
 
 @not_rpython
 def next_garbage_pypy(Class):
-    return lltype.nullptr(llmemory.GCREF.TO)
+    return None
 
 @not_rpython
-def next_garbage_pyobj(OB_PTR_TYPE):
+def next_garbage_pyobj(OB_PTR_TYPE, curr_pyobj):
     return lltype.nullptr(OB_PTR_TYPE.TO)
 
 @not_rpython
@@ -375,8 +375,7 @@
         return _spec_p(hop, v_p)
 
 class Entry(ExtRegistryEntry):
-    _about_ = (next_dead, cyclic_garbage_head, next_cyclic_isolate,
-               next_garbage_pyobj)
+    _about_ = (next_dead, cyclic_garbage_head, next_cyclic_isolate)
 
     def compute_result_annotation(self, s_OB_PTR_TYPE):
         from rpython.rtyper.llannotation import lltype_to_annotation
@@ -390,13 +389,28 @@
             name = 'gc_rawrefcount_cyclic_garbage_head'
         elif self.instance is next_cyclic_isolate:
             name = 'gc_rawrefcount_next_cyclic_isolate'
-        elif self.instance is next_garbage_pyobj:
-            name = 'gc_rawrefcount_next_garbage_pyobj'
         hop.exception_cannot_occur()
         v_ob = hop.genop(name, [], resulttype = llmemory.Address)
         return _spec_ob(hop, v_ob)
 
 class Entry(ExtRegistryEntry):
+    _about_ = next_garbage_pyobj
+
+    def compute_result_annotation(self, s_OB_PTR_TYPE, s_ob):
+        from rpython.rtyper.llannotation import lltype_to_annotation, SomePtr
+        assert s_OB_PTR_TYPE.is_constant()
+        assert isinstance(s_ob, SomePtr)
+        return lltype_to_annotation(s_OB_PTR_TYPE.const)
+
+    def specialize_call(self, hop):
+        hop.exception_cannot_occur()
+        v_ob = hop.inputarg(hop.args_r[1], arg=1)
+        v_ob_res = hop.genop('gc_rawrefcount_next_garbage_pyobj',
+                             [_unspec_ob(hop, v_ob)],
+                             resulttype = llmemory.Address)
+        return _spec_ob(hop, v_ob_res)
+
+class Entry(ExtRegistryEntry):
     _about_ = next_garbage_pypy
 
     def compute_result_annotation(self, s_Class):


More information about the pypy-commit mailing list