[pypy-commit] pypy cpyext-gc-cycle: Fixed tests for non-gc proxies in incmark

stevie_92 pypy.commits at gmail.com
Sat Sep 21 10:43:27 EDT 2019


Author: Stefan Beyer <home at sbeyer.at>
Branch: cpyext-gc-cycle
Changeset: r97577:2606a6511ff0
Date: 2019-09-21 09:43 +0200
http://bitbucket.org/pypy/pypy/changeset/2606a6511ff0/

Log:	Fixed tests for non-gc proxies in incmark

diff --git a/rpython/memory/gc/rrc/incmark.py b/rpython/memory/gc/rrc/incmark.py
--- a/rpython/memory/gc/rrc/incmark.py
+++ b/rpython/memory/gc/rrc/incmark.py
@@ -13,11 +13,6 @@
             return True
 
         if self.state == self.STATE_DEFAULT:
-            # For all non-gc pyobjects which have a refcount > 0,
-            # mark all reachable objects on the pypy side
-            self.p_list_old.foreach(self._major_trace_nongc, False)
-            # TODO: execute incrementally (own phase)
-
             # Merge all objects whose finalizer have been executed to the
             # pyobj_list (to reprocess them again in the snapshot). Finalizers
             # can only be executed once, so termination will eventually happen.
@@ -72,10 +67,29 @@
         #  * move all dead objects still in pyob_list to pyobj_old_list
         #  * for all other objects (in snapshot and new),
         #    set their cyclic refcount to > 0 to mark them as live
-        pygchdr = self.pyobj_list.c_gc_next
         consistent = True
         self.snapshot_consistent = True
-        while pygchdr <> self.pyobj_list: # TODO: also sync p_list
+        # simply iterate the snapshot for objects in p_list, as linked objects might not be freed, except by the gc
+        free_p_list = self.gc.AddressStack()
+        for i in range(0, self.total_objs):
+            snapobj = self.snapshot_objs[i]
+            if snapobj.pypy_link == 0:
+                break
+            pyobj = llmemory.cast_adr_to_ptr(snapobj.pyobj, self.PYOBJ_HDR_PTR)
+            pygchdr = self.pyobj_as_gc(pyobj)
+            if (pygchdr <> lltype.nullptr(self.PYOBJ_GC_HDR) and
+                    pygchdr.c_gc_refs != self.RAWREFCOUNT_REFS_UNTRACKED):
+                break
+            if snapobj.refcnt == 0:
+                consistent = pyobj.c_ob_refcnt == snapobj.refcnt_original
+                if not consistent:
+                    break
+                # move to separate list
+                free_p_list.append(snapobj.pyobj)
+
+        # sync gc objects
+        pygchdr = self.pyobj_list.c_gc_next
+        while pygchdr <> self.pyobj_list and consistent:
             next_old = pygchdr.c_gc_next
             if pygchdr.c_gc_refs > 0: # object is in snapshot
                 snapobj = self.snapshot_objs[pygchdr.c_gc_refs - 1]
@@ -105,6 +119,8 @@
         self._debug_check_consistency(print_label="end-check-consistency")
 
         if not consistent:  # keep all objects alive
+            while free_p_list.non_empty():
+                self.p_list_old.append(free_p_list.pop())
             while pygchdr <> self.pyobj_list: # continue previous loop
                 pygchdr.c_gc_refs = 1
                 pygchdr = pygchdr.c_gc_next
@@ -114,6 +130,8 @@
                 pygchdr = pygchdr.c_gc_next
             if not self._gc_list_is_empty(self.pyobj_old_list):
                 self._gc_list_merge(self.pyobj_old_list, self.pyobj_list)
+        else:
+            free_p_list.foreach(self._free_p_list, None)
 
         self._debug_check_consistency(print_label="before-snap-discard")
 
@@ -140,6 +158,19 @@
         self._debug_check_consistency(print_label="end-mark")
         return True
 
+    def _free_p_list(self, pyobject, foo):
+        from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
+        from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
+        # unlink
+        self.p_list_old.remove(pyobject)
+        pyobj = llmemory.cast_adr_to_ptr(pyobject, self.PYOBJ_HDR_PTR)
+        refcnt = pyobj.c_ob_refcnt
+        if refcnt >= REFCNT_FROM_PYPY_LIGHT:
+            refcnt -= REFCNT_FROM_PYPY_LIGHT
+        elif refcnt >= REFCNT_FROM_PYPY:
+            refcnt -= REFCNT_FROM_PYPY
+        pyobj.c_ob_refcnt = refcnt
+
     def _collect_roots(self):
         # Subtract all internal refcounts from the cyclic refcount
         # of rawrefcounted objects
diff --git a/rpython/memory/gc/test/dot/keep_cross_nogc_1.dot b/rpython/memory/gc/test/dot/keep_nocycle_nogc_1.dot
copy from rpython/memory/gc/test/dot/keep_cross_nogc_1.dot
copy to rpython/memory/gc/test/dot/keep_nocycle_nogc_1.dot
--- a/rpython/memory/gc/test/dot/keep_cross_nogc_1.dot
+++ b/rpython/memory/gc/test/dot/keep_nocycle_nogc_1.dot
@@ -1,12 +1,7 @@
 digraph G {
-    "a" [type=P, alive=y];
-    "b" [type=B, alive=y];
-    "c" [type=C, alive=y];
-    "d" [type=B, alive=y, gc=n];
-    "e" [type=P, alive=y, rooted=y];
+    "a" [type=C, alive=y, ext_refcnt=1];
+    "b" [type=B, alive=y, gc=n];
+    "c" [type=P, alive=y];
     "a" -> "b";
     "b" -> "c";
-    "c" -> "d";
-    "d" -> "a";
-    "e" -> "d";
 }
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
@@ -26,8 +26,8 @@
 
 class TestRawRefCount(BaseDirectGCTest):
     GCClass = IncMiniMark
-    #RRCGCClass = RawRefCountIncMarkGC
-    RRCGCClass = RawRefCountMarkGC
+    RRCGCClass = RawRefCountIncMarkGC
+    #RRCGCClass = RawRefCountMarkGC
 
     def setup_method(self, method):
         BaseDirectGCTest.setup_method(self, method)
@@ -773,24 +773,19 @@
         for name in nodes:
             n = nodes[name]
             if n.info.alive:
+                print "Node", name, "should be alive."
                 if n.info.type == "P":
                     n.check_alive()
                 else:
                     n.check_alive(n.info.ext_refcnt)
+                print "Node", name, "is alive."
             else:
+                print "Node", name, "should be dead."
                 if n.info.type == "P":
                     py.test.raises(RuntimeError, "n.p.x")  # dead
                 else:
                     py.test.raises(RuntimeError, "n.r.c_ob_refcnt")  # dead
-
-        # check if all callbacks from weakrefs from cyclic garbage structures,
-        # which should not be called because they could ressurrect dead
-        # objects, have been cleared and no other callbacks were cleared; see:
-        # https://github.com/python/cpython/blob/master/Modules/gc_weakref.txt
-        for weakrefs in self.pyobj_weakrefs:
-            for weakref in weakrefs:
-                pass # TODO fix
-                #assert weakref.callback_cleared == weakref.clear_callback
+                print "Node", name, "is dead."
 
         # check if unreachable objects in cyclic structures with legacy
         # finalizers and all otherwise unreachable objects reachable from them


More information about the pypy-commit mailing list