[pypy-commit] pypy cpyext-gc-cycle: Simplified handling of rrc modern finalizers

stevie_92 pypy.commits at gmail.com
Sat Sep 7 04:39:09 EDT 2019


Author: Stefan Beyer <home at sbeyer.at>
Branch: cpyext-gc-cycle
Changeset: r97391:7bc15233822f
Date: 2019-09-07 10:38 +0200
http://bitbucket.org/pypy/pypy/changeset/7bc15233822f/

Log:	Simplified handling of rrc modern finalizers Added TODOs to improve
	pause times in rrc incmark Fixed bug in rrc mark

diff --git a/rpython/memory/gc/rrc/base.py b/rpython/memory/gc/rrc/base.py
--- a/rpython/memory/gc/rrc/base.py
+++ b/rpython/memory/gc/rrc/base.py
@@ -543,33 +543,10 @@
             self.gc.trace(obj, self._collect_ref_rec, None)
         return True
 
-    def _check_finalizer(self):
-        # Check, if the cyclic isolate from the last collection cycle
-        # is reachable from outside, after the finalizers have been
-        # executed (and if all finalizers have been executed).
-        found_alive = self._gc_list_is_empty(self.pyobj_isolate_list)
-        if not found_alive:
-            found_alive = self._find_finalizer()
-        if not found_alive:
-            self._collect_roots(self.pyobj_old_list)
-            gchdr = self.pyobj_old_list.c_gc_next
-            while gchdr <> self.pyobj_old_list:
-                if (gchdr.c_gc_refs >> self.RAWREFCOUNT_REFS_SHIFT) > 0:
-                    found_alive = True
-                    break
-                gchdr = gchdr.c_gc_next
-        if found_alive:
-            self._gc_list_merge(self.pyobj_old_list, self.pyobj_list)
-            return False
-        else:
-            self._gc_list_merge(self.pyobj_old_list, self.pyobj_dead_list)
-            return True
-
     def _find_finalizer(self):
         gchdr = self.pyobj_old_list.c_gc_next
         while gchdr <> self.pyobj_old_list:
-            if self.finalizer_type(gchdr) == \
-                    self.RAWREFCOUNT_FINALIZER_MODERN:
+            if self.finalizer_type(gchdr) == self.RAWREFCOUNT_FINALIZER_MODERN:
                 return True
             gchdr = gchdr.c_gc_next
         return False
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,35 +13,30 @@
             return True
 
         if self.state == self.STATE_DEFAULT:
-            # First, untrack all tuples with only non-gc rrc objects and
+            # 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.
+            # Objects which have not been resurrected should be freed during
+            # this cycle.
+            if not self._gc_list_is_empty(self.pyobj_old_list):
+                self._gc_list_merge(self.pyobj_old_list, self.pyobj_list)
+
+            # Untrack all tuples with only non-gc rrc objects and
             # promote all other tuples to the pyobj_list
             self._untrack_tuples()
-
-            merged_old_list = False
-            # check objects with finalizers from last collection cycle
-            if not self._gc_list_is_empty(self.pyobj_old_list):
-                merged_old_list = self._check_finalizer()
-
-            # 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? (before snapshot!)
 
             # Now take a snapshot
             self._take_snapshot(self.pyobj_list)
 
             # collect all rawrefcounted roots
-            self._collect_roots(self.pyobj_list)
+            self._collect_roots()
+            # TODO: execute incrementally (own phase, save index)
 
-            if merged_old_list:
-                # set all refcounts to zero for objects in dead list
-                # (might have been incremented) by fix_refcnt
-                gchdr = self.pyobj_dead_list.c_gc_next
-                while gchdr <> self.pyobj_dead_list:
-                    if (gchdr.c_gc_refs > 0 and gchdr.c_gc_refs !=
-                            self.RAWREFCOUNT_REFS_UNTRACKED):
-                        pyobj = self.snapshot_objs[gchdr.c_gc_refs - 1]
-                        pyobj.refcnt_external = 0
-                    gchdr = gchdr.c_gc_next
+            # 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
 
             self._debug_check_consistency(print_label="roots-marked")
             self.state = self.STATE_MARKING
@@ -50,6 +45,7 @@
         if self.state == self.STATE_MARKING:
             # mark all objects reachable from rawrefcounted roots
             all_rrc_marked = self._mark_rawrefcount()
+            # TODO: execute incrementally
 
             if (all_rrc_marked and not self.gc.objects_to_trace.non_empty() and
                     not self.gc.more_objects_to_trace.non_empty()):
@@ -136,7 +132,7 @@
         self._debug_check_consistency(print_label="end-mark")
         return True
 
-    def _collect_roots(self, pygclist):
+    def _collect_roots(self):
         # Subtract all internal refcounts from the cyclic refcount
         # of rawrefcounted objects
         for i in range(0, self.total_objs):
diff --git a/rpython/memory/gc/rrc/mark.py b/rpython/memory/gc/rrc/mark.py
--- a/rpython/memory/gc/rrc/mark.py
+++ b/rpython/memory/gc/rrc/mark.py
@@ -4,6 +4,8 @@
 
 class RawRefCountMarkGC(RawRefCountBaseGC):
 
+    use_refcntdict = False
+
     def major_collection_trace_step(self):
         if not self.cycle_enabled:
             self._debug_check_consistency(print_label="begin-mark")
@@ -18,28 +20,30 @@
         # Only trace and mark rawrefcounted object if we are not doing
         # something special, like building gc.garbage.
         if self.state == self.STATE_MARKING and self.cycle_enabled:
-            merged_old_list = False
-            # check objects with finalizers from last collection cycle
+            # 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.
+            # Objects which have not been resurrected should be freed during
+            # this cycle.
             if not self._gc_list_is_empty(self.pyobj_old_list):
-                merged_old_list = self._check_finalizer()
+                self._gc_list_merge(self.pyobj_old_list, self.pyobj_list)
+
             # collect all rawrefcounted roots
-            self._collect_roots(self.pyobj_list)
-            if merged_old_list:
-                # set all refcounts to zero for objects in dead list
-                # (might have been incremented) by fix_refcnt
-                gchdr = self.pyobj_dead_list.c_gc_next
-                while gchdr <> self.pyobj_dead_list:
-                    gchdr.c_gc_refs = 0
-                    gchdr = gchdr.c_gc_next
+            self._collect_roots()
             self._debug_check_consistency(print_label="roots-marked")
+
             # mark all objects reachable from rawrefcounted roots
             self._mark_rawrefcount()
             self._debug_check_consistency(print_label="before-fin")
+
+            # handle legacy finalizer
             self.state = self.STATE_GARBAGE_MARKING
-            if self._find_garbage(True): # handle legacy finalizers
+            if self._find_garbage(True):
                 self._mark_garbage(True)
                 self._debug_check_consistency(print_label="end-legacy-fin")
             self.state = self.STATE_MARKING
+
+            # handle modern finalizer
             found_finalizer = self._find_finalizer()
             if found_finalizer:
                 self._gc_list_move(self.pyobj_old_list,
@@ -71,9 +75,9 @@
                 self._pyobj(pyobject).c_ob_pypy_link)
         return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
 
-    def _collect_roots(self, pygclist):
+    def _collect_roots(self):
         # Initialize the cyclic refcount with the real refcount.
-        self._collect_roots_init_list(pygclist)
+        self._collect_roots_init_list(self.pyobj_list)
 
         # Save the real refcount of objects at border
         self.p_list_old.foreach(self._obj_save_refcnt, None)
@@ -82,7 +86,7 @@
 
         # Subtract all internal refcounts from the cyclic refcount
         # of rawrefcounted objects
-        self._collect_roots_subtract_internal(pygclist)
+        self._collect_roots_subtract_internal(self.pyobj_list)
 
         # For all non-gc pyobjects which have a refcount > 0,
         # mark all reachable objects on the pypy side


More information about the pypy-commit mailing list