Author: Stefan Beyer <[email protected]>
Branch: cpyext-gc-cycle
Changeset: r96225:5d1c0b97ef5a
Date: 2019-03-08 14:23 +0100
http://bitbucket.org/pypy/pypy/changeset/5d1c0b97ef5a/

Log:    Implemented garbage_pypy and improved tests

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
@@ -3141,6 +3141,7 @@
             self.rrc_pyobj_isolate_list = self._rrc_gc_list_new()
             self.rrc_pyobj_dead_list = self._rrc_gc_list_new()
             self.rrc_pyobj_garbage_list = self._rrc_gc_list_new()
+            self.rrc_garbage_to_trace = self.AddressStack()
             self.rrc_gc_as_pyobj = gc_as_pyobj
             self.rrc_pyobj_as_gc = pyobj_as_gc
             self.rrc_finalizer_type = finalizer_type
@@ -3246,15 +3247,14 @@
         self.rrc_state = self.RAWREFCOUNT_STATE_DEFAULT
 
     def rawrefcount_next_garbage_pypy(self):
-        # We assume that next_garbage_pypy is always called before
-        # next_garbage_pyobj. As pypy objects can only be in garbage, if there
-        # is at least one pyobj in garbage, we can use this optimization.
-        if self._rrc_gc_list_is_empty(self.rrc_pyobj_garbage_list):
-            return lltype.nullptr(llmemory.GCREF.TO)
+        if self.rrc_garbage_to_trace.non_empty():
+            # remove one object from the wavefront and move the wavefront
+            obj = self.rrc_garbage_to_trace.pop()
+            if self._rrc_garbage_visit(obj):
+                return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
+            else:
+                return lltype.nullptr(llmemory.GCREF.TO)
         else:
-            # TODO: return the next pypy object which is marked with 
GCFLAG_GARBAGE and
-            #       remove the flag from this object. We can safely assume 
that objects
-            #       do not move, as this can only happen to old objects.
             return lltype.nullptr(llmemory.GCREF.TO)
 
     def rawrefcount_next_garbage_pyobj(self):
@@ -3620,9 +3620,28 @@
         if pyobj.c_ob_pypy_link <> 0:
             intobj = pyobj.c_ob_pypy_link
             obj = llmemory.cast_int_to_adr(intobj)
+            self.rrc_garbage_to_trace.append(obj)
             self.objects_to_trace.append(obj)
             self.visit_all_objects()
 
+    def _rrc_collect_obj(self, obj, ignored):
+        llop.debug_nonnull_pointer(lltype.Void, obj)
+        self.rrc_garbage_to_trace.append(obj)
+    _rrc_collect_obj._always_inline_ = True
+
+    def _rrc_collect_ref_rec(self, root, ignored):
+        self._rrc_collect_obj(root.address[0], None)
+
+    def _rrc_garbage_visit(self, obj):
+        # If GCFLAG_GARBAGE is set, remove the flag and trace the object
+        hdr = self.header(obj)
+        if not (hdr.tid & GCFLAG_GARBAGE):
+            return False
+        hdr.tid &= ~GCFLAG_GARBAGE
+        if self.has_gcptr(llop.extract_ushort(llgroup.HALFWORD, hdr.tid)):
+            self.trace(obj, self._rrc_collect_ref_rec, None)
+        return True
+
     def _rrc_check_finalizer(self):
         # Check, if the cyclic isolate from the last collection cycle
         # is reachable from outside, after the finalizers have been
diff --git a/rpython/memory/gc/test/dot/garbage_cross_simple_1.dot 
b/rpython/memory/gc/test/dot/garbage_cross_simple_1.dot
--- a/rpython/memory/gc/test/dot/garbage_cross_simple_1.dot
+++ b/rpython/memory/gc/test/dot/garbage_cross_simple_1.dot
@@ -3,8 +3,12 @@
     "b" [type=B, alive=y, garbage=y];
     "c" [type=P, alive=y, garbage=y];
     "d" [type=P, alive=y, rooted=y];
+    "e" [type=C, alive=y, garbage=y];
+    "f" [type=C, alive=y, ext_refcnt=1];
     "a" -> "b";
     "b" -> "a";
     "b" -> "c";
     "c" -> "d";
+    "a" -> "e";
+    "a" -> "f";
 }
\ No newline at end of file
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
@@ -672,10 +672,15 @@
         # have been added to the garbage list
         for name in nodes:
             n = nodes[name]
+            garbage = n.info.garbage
             if n.info.alive:
                 if n.info.type == "C":
-                    assert n.info.garbage != (n.raddr not in garbage_pyobj)
+                    assert garbage != (n.raddr not in garbage_pyobj), \
+                        "PyObject should " + ("" if garbage else "not ") + \
+                        "be in garbage"
                 else:
-                    assert n.info.garbage != (n.pref not in garbage_pypy)
+                    assert garbage != (n.pref not in garbage_pypy), \
+                        "Object should " + ("" if garbage else "not ") + \
+                        "be in garbage"
             else:
-                assert not n.info.garbage
\ No newline at end of file
+                assert not garbage, "Object is dead, but should be in garbage"
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to