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

stevie_92 pypy.commits at gmail.com
Mon Sep 23 17:40:04 EDT 2019


Author: Stefan Beyer <home at sbeyer.at>
Branch: cpyext-gc-cycle
Changeset: r97595:7818db583143
Date: 2019-09-23 23:39 +0200
http://bitbucket.org/pypy/pypy/changeset/7818db583143/

Log:	Fixed handling of modern finalizers in rrc gc Fixed test cases

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
@@ -109,6 +109,8 @@
         self.tuple_list = self._pygchdr(tuple_list)
         self.pyobj_old_list = self._gc_list_new()
         self.pyobj_isolate_list = self._gc_list_new()
+        self.pyobj_isolate_old_list = self._gc_list_new()
+        self.pyobj_isolate_dead_list = self._gc_list_new()
         self.pyobj_dead_list = self._gc_list_new()
         self.pyobj_garbage_list = self._gc_list_new()
         self.garbage_to_trace = self.gc.AddressStack()
@@ -177,7 +179,7 @@
     def next_cyclic_isolate(self):
         if not self._gc_list_is_empty(self.pyobj_isolate_list):
             gchdr = self._gc_list_pop(self.pyobj_isolate_list)
-            self._gc_list_add(self.pyobj_old_list, gchdr)
+            self._gc_list_add(self.pyobj_isolate_old_list, gchdr)
             return llmemory.cast_ptr_to_adr(self.gc_as_pyobj(gchdr))
         return llmemory.NULL
 
@@ -546,37 +548,9 @@
             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). Return
-        # True if some objects are reachable and thus have been resurrected.
-
-        # check if the list has been fully processed since the last cycle
-        # (for safety)
-        found_alive = not self._gc_list_is_empty(self.pyobj_isolate_list)
-
-        # check if all finalizers have actually been called (for safety)
-        if not found_alive:
-            found_alive = self._find_finalizer()
-
-        # check if there are any objects with a reference count > 0
-        if not found_alive:
-            gchdr = self.pyobj_old_list.c_gc_next
-            while gchdr <> self.pyobj_old_list:
-                if True: # TODO: check refcount or marked (see _collect_roots)
-                    found_alive = True
-                    break
-                gchdr = gchdr.c_gc_next
-
-        if found_alive:
-            self._gc_list_merge(self.pyobj_old_list, self.pyobj_list)
+    def _find_finalizer(self):
+        if not self._gc_list_is_empty(self.pyobj_isolate_list):
             return True
-        else:
-            self._gc_list_merge(self.pyobj_old_list, self.pyobj_dead_list)
-            return False
-
-    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:
@@ -699,6 +673,8 @@
                                    "pyobj_dead_list")
             self._debug_check_list(self.pyobj_isolate_list, should_print,
                                    "pyobj_isolate_list")
+            self._debug_check_list(self.pyobj_isolate_old_list, should_print,
+                                   "pyobj_isolate_old_list")
             # pyobj_garbage_list is not a real list, it just marks the
             # first and the last object in pyobj_list, which are garbage
 
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
@@ -6,35 +6,21 @@
 class RawRefCountIncMarkGC(RawRefCountBaseGC):
 
     def major_collection_trace_step(self):
-        if not self.cycle_enabled or self.state == self.STATE_GARBAGE:
+        if (not self.cycle_enabled or self.state == self.STATE_GARBAGE or
+                not self._gc_list_is_empty(self.pyobj_isolate_list)):
             self._debug_check_consistency(print_label="begin-mark")
             self.p_list_old.foreach(self._major_trace, (False, False))
             self._debug_check_consistency(print_label="end-mark")
             return True
 
         if self.state == self.STATE_DEFAULT:
-            # 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)
-            # TODO: use separate list and process it after pyobj_list has been
-            #       fully processed (just before modern finalizers) if references
-            #       to separate list are encountered during take_snapshot
-            #       move them to pyobj_list and include them in the snapshot.
-            #       For the remaining list (before modern finalizers), check
-            #       if there are external references from marked non-rc objects
-            #       (rc objects were already detected during take_snapshot)
-
-            # Untrack all tuples with only non-gc rrc objects and
+            # untrack all tuples with only non-gc rrc objects and
             # promote all other tuples to the pyobj_list
             self._untrack_tuples()
             # TODO: execute incrementally? (before snapshot!, own phase)
 
-            # Now take a snapshot
-            self._take_snapshot(self.pyobj_list)
+            # now take a snapshot
+            self._take_snapshot()
             self._debug_print_snap(print_label="after-snapshot")
 
             # collect all rawrefcounted roots
@@ -65,97 +51,8 @@
         # we are finished with marking, now finish things up
         ll_assert(self.state == self.STATE_GARBAGE_MARKING, "invalid state")
 
-        # sync snapshot with pyob_list:
-        #  * check the consistency of "dead" objects and keep all of them
-        #    alive, in case an inconsistency is found (the graph changed
-        #    between two pauses, so some of those objects might be alive)
-        #  * 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
-        consistent = True
-        self.snapshot_consistent = True
-
-        # sync p_list_old (except gc-objects)
-        # 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  # only look for objects in p_list
-            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 # only look for non-gc
-            if snapobj.refcnt == 0:
-                # check consistency
-                consistent = pyobj.c_ob_refcnt == snapobj.refcnt_original
-                if not consistent:
-                    break
-                # move to separate list
-                self.p_list_old.remove(snapobj.pyobj)
-                free_p_list.append(snapobj.pyobj)
-
-        # look if there is a (newly) linked non-gc proxy, where the non-rc obj
-        # is unmarked
-        self.p_list_old_consistent = True
-        self.p_list_old.foreach(self._check_consistency_p_list_old, None)
-        consistent &= self.p_list_old_consistent
-
-        # 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]
-                pygchdr.c_gc_refs = snapobj.refcnt
-                if snapobj.refcnt == 0: # object considered dead
-                    # check consistency (dead subgraphs can never change):
-                    pyobj = self.gc_as_pyobj(pygchdr)
-                    # refcount equal
-                    consistent = snapobj.refcnt_original == pyobj.c_ob_refcnt
-                    if not consistent:
-                        break
-                    # outgoing (internal) references equal
-                    self.snapshot_curr = snapobj
-                    self.snapshot_curr_index = 0
-                    self._check_snapshot_traverse(pyobj)
-                    consistent = self.snapshot_consistent
-                    if not consistent:
-                        break
-                    # consistent -> prepare object for collection
-                    self._gc_list_remove(pygchdr)
-                    self._gc_list_add(self.pyobj_old_list, pygchdr)
-            else:
-                # new object, keep alive
-                pygchdr.c_gc_refs = 1 << self.RAWREFCOUNT_REFS_SHIFT
-                pyobj = self.gc_as_pyobj(pygchdr)
-                if pyobj.c_ob_pypy_link != 0:
-                    addr = llmemory.cast_int_to_adr(pyobj.c_ob_pypy_link)
-                    if not (self.gc.header(addr).tid &
-                            (self.GCFLAG_VISITED | self.GCFLAG_NO_HEAP_PTRS)):
-                        consistent = False
-                        break
-            pygchdr = next_old
-
-        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 << self.RAWREFCOUNT_REFS_SHIFT
-                pygchdr = pygchdr.c_gc_next
-            pygchdr = self.pyobj_old_list.c_gc_next
-            while pygchdr <> self.pyobj_old_list: # resurrect "dead" objects
-                pygchdr.c_gc_refs = 1 << self.RAWREFCOUNT_REFS_SHIFT
-                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)
-
+        # sync snapshot
+        self._sync_snapshot()
         self._debug_check_consistency(print_label="before-snap-discard")
 
         # now the snapshot is not needed any more, discard it
@@ -181,6 +78,147 @@
         self._debug_check_consistency(print_label="end-mark")
         return True
 
+    def _sync_snapshot(self):
+        # sync snapshot with pyob_list:
+        #  * check the consistency of "dead" objects and keep all of them
+        #    alive, in case an inconsistency is found (the graph changed
+        #    between two pauses, so some of those objects might be alive)
+        #  * 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
+        consistent = True
+        self.snapshot_consistent = True
+
+        # sync p_list_old (except gc-objects)
+        # 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  # only look for objects in p_list
+            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  # only look for non-gc
+            if snapobj.refcnt == 0:
+                # check consistency
+                consistent = pyobj.c_ob_refcnt == snapobj.refcnt_original
+                if not consistent:
+                    break
+                # move to separate list
+                self.p_list_old.remove(snapobj.pyobj)
+                free_p_list.append(snapobj.pyobj)
+
+        # look if there is a (newly) linked non-gc proxy, where the non-rc obj
+        # is unmarked
+        self.p_list_old_consistent = True
+        self.p_list_old.foreach(self._check_consistency_p_list_old, None)
+        consistent &= self.p_list_old_consistent
+
+        # 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
+                consistent = self._check_consistency_gc(pygchdr,
+                                                        self.pyobj_old_list)
+                if not consistent:
+                    break
+            else:
+                # new object, keep alive
+                pygchdr.c_gc_refs = 1 << self.RAWREFCOUNT_REFS_SHIFT
+                pyobj = self.gc_as_pyobj(pygchdr)
+                if pyobj.c_ob_pypy_link != 0:
+                    addr = llmemory.cast_int_to_adr(pyobj.c_ob_pypy_link)
+                    if not (self.gc.header(addr).tid &
+                            (self.GCFLAG_VISITED | self.GCFLAG_NO_HEAP_PTRS)):
+                        consistent = False
+                        break
+            pygchdr = next_old
+        pygchdr_continue_gc = pygchdr
+
+        # sync isolate objs
+        isolate_consistent = True
+        pygchdr = self.pyobj_isolate_old_list.c_gc_next
+        while pygchdr <> self.pyobj_isolate_old_list and isolate_consistent:
+            next_old = pygchdr.c_gc_next
+            isolate_consistent = \
+                self._check_consistency_gc(pygchdr,
+                                           self.pyobj_isolate_dead_list)
+            pygchdr = next_old
+        pygchdr_continue_isolate = pygchdr
+        consistent &= isolate_consistent
+        self._debug_check_consistency(print_label="end-check-consistency")
+
+        if consistent:
+            free_p_list.foreach(self._free_p_list, None)
+        else:
+            # keep linked non-gc alive
+            while free_p_list.non_empty():
+                self.p_list_old.append(free_p_list.pop())
+            # continue previous loop, keep objects alive
+            pygchdr = pygchdr_continue_gc
+            while pygchdr <> self.pyobj_list:
+                pygchdr.c_gc_refs = 1 << self.RAWREFCOUNT_REFS_SHIFT
+                pygchdr = pygchdr.c_gc_next
+            pygchdr = self.pyobj_old_list.c_gc_next
+            # resurrect "dead" objects
+            while pygchdr <> self.pyobj_old_list:
+                pygchdr.c_gc_refs = 1 << self.RAWREFCOUNT_REFS_SHIFT
+                pygchdr = pygchdr.c_gc_next
+            # merge lists
+            if not self._gc_list_is_empty(self.pyobj_old_list):
+                self._gc_list_merge(self.pyobj_old_list, self.pyobj_list)
+
+        if isolate_consistent:
+            if not self._gc_list_is_empty(self.pyobj_isolate_old_list):
+                self._gc_list_merge(self.pyobj_isolate_old_list,
+                                    self.pyobj_list)
+            if not self._gc_list_is_empty(self.pyobj_isolate_dead_list):
+                self._gc_list_merge(self.pyobj_isolate_dead_list,
+                                    self.pyobj_dead_list)
+        else:
+            # continue previous loop, keep objects alive
+            pygchdr = pygchdr_continue_isolate
+            while pygchdr <> self.pyobj_isolate_old_list:
+                pygchdr.c_gc_refs = 1 << self.RAWREFCOUNT_REFS_SHIFT
+                pygchdr = pygchdr.c_gc_next
+            # resurrect "dead" objects
+            while pygchdr <> self.pyobj_isolate_dead_list:
+                pygchdr.c_gc_refs = 1 << self.RAWREFCOUNT_REFS_SHIFT
+                pygchdr = pygchdr.c_gc_next
+            # merge lists
+            if not self._gc_list_is_empty(self.pyobj_isolate_old_list):
+                self._gc_list_merge(self.pyobj_isolate_old_list,
+                                    self.pyobj_list)
+            if not self._gc_list_is_empty(self.pyobj_isolate_dead_list):
+                self._gc_list_merge(self.pyobj_isolate_dead_list,
+                                    self.pyobj_list)
+
+    def _check_consistency_gc(self, pygchdr, pylist_dead_target):
+        snapobj = self.snapshot_objs[pygchdr.c_gc_refs - 1]
+        pygchdr.c_gc_refs = snapobj.refcnt
+        if snapobj.refcnt == 0:  # object considered dead
+            # check consistency (dead subgraphs can never change):
+            pyobj = self.gc_as_pyobj(pygchdr)
+            # refcount equal
+            consistent = snapobj.refcnt_original == pyobj.c_ob_refcnt
+            if not consistent:
+                return False
+            # outgoing (internal) references equal
+            self.snapshot_curr = snapobj
+            self.snapshot_curr_index = 0
+            self._check_snapshot_traverse(pyobj)
+            consistent = self.snapshot_consistent
+            if not consistent:
+                return False
+            # consistent -> prepare object for collection
+            self._gc_list_remove(pygchdr)
+            self._gc_list_add(pylist_dead_target, pygchdr)
+        return True
+
     def _debug_print_snap(self, print_label=None):
         debug_start("snap " + print_label)
         for i in range(0, self.total_objs):
@@ -272,21 +310,19 @@
             snapobj.status = 0
         return alive
 
-    def _take_snapshot(self, pygclist):
-        from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
-        from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
+    def _take_snapshot(self):
+        total_refcnt = 0
+        total_objs = 0
 
         # calculate size of memory buffer for snapshot
-        total_refcnt = 0
-        total_objs = 0
-        pygchdr = pygclist.c_gc_next
-        while pygchdr <> pygclist:
-            refcnt = self.gc_as_pyobj(pygchdr).c_ob_refcnt
-            if refcnt >= REFCNT_FROM_PYPY_LIGHT:
-                refcnt -= REFCNT_FROM_PYPY_LIGHT
-            elif refcnt >= REFCNT_FROM_PYPY:
-                refcnt -= REFCNT_FROM_PYPY
-            total_refcnt += refcnt
+        pygchdr = self.pyobj_list.c_gc_next
+        while pygchdr <> self.pyobj_list:
+            total_refcnt += self._take_snapshot_count_gc(pygchdr)
+            total_objs += 1
+            pygchdr = pygchdr.c_gc_next
+        pygchdr = self.pyobj_isolate_old_list.c_gc_next
+        while pygchdr <> self.pyobj_isolate_old_list:
+            total_refcnt += self._take_snapshot_count_gc(pygchdr)
             total_objs += 1
             pygchdr = pygchdr.c_gc_next
         self.p_list_count = 0
@@ -309,33 +345,16 @@
         # take snapshot of p_list_old
         self.p_list_old.foreach(self._take_snapshot_pyobject, None)
 
-        # take snapshot of gc objs TODO: include finalizer_list from last cycle
-        pygchdr = pygclist.c_gc_next
-        while pygchdr <> pygclist:
-            pyobj = self.gc_as_pyobj(pygchdr)
-            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
-            if pyobj.c_ob_pypy_link != 0:
-                addr = llmemory.cast_int_to_adr(pyobj.c_ob_pypy_link)
-                if self.gc.header(addr).tid & (self.GCFLAG_VISITED |
-                                              self.GCFLAG_NO_HEAP_PTRS):
-                    refcnt += 1
-            pygchdr.c_gc_refs = self.objs_index + 1
-            obj = self.snapshot_objs[self.objs_index]
-            obj.pyobj = llmemory.cast_ptr_to_adr(pyobj)
-            obj.status = 1
-            obj.refcnt_original = pyobj.c_ob_refcnt
-            obj.refcnt = refcnt
-            obj.refs_index = self.refs_index
-            obj.refs_len = 0
-            obj.pypy_link = pyobj.c_ob_pypy_link
-            self.snapshot_curr = obj
-            self._take_snapshot_traverse(pyobj)
-            self.objs_index += 1
-            self.refs_index += obj.refs_len
+        # take snapshot of gc objs
+        pygchdr = self.pyobj_list.c_gc_next
+        while pygchdr <> self.pyobj_list:
+            self._take_snapshot_gc(pygchdr)
+            pygchdr = pygchdr.c_gc_next
+
+        # include isolates from last cycle
+        pygchdr = self.pyobj_isolate_old_list.c_gc_next
+        while pygchdr <> self.pyobj_isolate_old_list:
+            self._take_snapshot_gc(pygchdr)
             pygchdr = pygchdr.c_gc_next
 
         # fix references
@@ -353,6 +372,46 @@
         # fix links of p_list_old back
         self.p_list_old.foreach(self._take_snapshot_fixlink, None)
 
+    def _take_snapshot_count_gc(self, pygchdr):
+        from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
+        from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
+        #
+        refcnt = self.gc_as_pyobj(pygchdr).c_ob_refcnt
+        if refcnt >= REFCNT_FROM_PYPY_LIGHT:
+            refcnt -= REFCNT_FROM_PYPY_LIGHT
+        elif refcnt >= REFCNT_FROM_PYPY:
+            refcnt -= REFCNT_FROM_PYPY
+        return refcnt
+
+    def _take_snapshot_gc(self, pygchdr):
+        from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
+        from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
+        #
+        pyobj = self.gc_as_pyobj(pygchdr)
+        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
+        if pyobj.c_ob_pypy_link != 0:
+            addr = llmemory.cast_int_to_adr(pyobj.c_ob_pypy_link)
+            if self.gc.header(addr).tid & (self.GCFLAG_VISITED |
+                                           self.GCFLAG_NO_HEAP_PTRS):
+                refcnt += 1
+        pygchdr.c_gc_refs = self.objs_index + 1
+        obj = self.snapshot_objs[self.objs_index]
+        obj.pyobj = llmemory.cast_ptr_to_adr(pyobj)
+        obj.status = 1
+        obj.refcnt_original = pyobj.c_ob_refcnt
+        obj.refcnt = refcnt
+        obj.refs_index = self.refs_index
+        obj.refs_len = 0
+        obj.pypy_link = pyobj.c_ob_pypy_link
+        self.snapshot_curr = obj
+        self._take_snapshot_traverse(pyobj)
+        self.objs_index += 1
+        self.refs_index += obj.refs_len
+
     def _take_snapshot_count(self, pyobject, foo):
         from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
         from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
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
@@ -18,30 +18,15 @@
         self._untrack_tuples()
 
         # 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:
-
-            # check if objects with finalizers from last collection cycle
-            # have been resurrected
-            dead_list_empty = True
-            if not self._gc_list_is_empty(self.pyobj_old_list):
-                dead_list_empty = self._check_finalizer()
-            # TODO: cannot work this way -> must first do full collection of
-            #       new graph, bc back ref over non-rrc from new rrc graph (#1)
-            # TODO: see incmark (instead of take_snapshot during collect_roots)
+        # something special, like building gc.garbage and if all finalizers
+        # have been processed.
+        if (self.state == self.STATE_MARKING and self.cycle_enabled and
+                self._gc_list_is_empty(self.pyobj_isolate_list)):
 
             # collect all rawrefcounted roots
             self._collect_roots()
             self._debug_check_consistency(print_label="roots-marked")
 
-            if not dead_list_empty:
-                # 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
-
             # mark all objects reachable from rawrefcounted roots
             self._mark_rawrefcount()
             self._debug_check_consistency(print_label="before-fin")
@@ -59,6 +44,9 @@
                 self._gc_list_move(self.pyobj_old_list,
                                    self.pyobj_isolate_list)
             use_cylicrc = not found_finalizer
+            if not self._gc_list_is_empty(self.pyobj_isolate_old_list):
+                self._gc_list_move(self.pyobj_isolate_old_list,
+                                   self.pyobj_old_list)
             self._debug_check_consistency(print_label="end-mark-cyclic")
 
             # mark all pypy objects at the border which are linked to live
@@ -90,6 +78,7 @@
     def _collect_roots(self):
         # Initialize the cyclic refcount with the real refcount.
         self._collect_roots_init_list(self.pyobj_list)
+        self._collect_roots_init_list(self.pyobj_isolate_old_list)
 
         # Save the real refcount of objects at border (they don't necessarily
         # have a rrc header, as not all of them are garbage collected on the
@@ -103,6 +92,7 @@
         # Subtract all internal refcounts from the cyclic refcount
         # of rawrefcounted objects
         self._collect_roots_subtract_internal(self.pyobj_list)
+        self._collect_roots_subtract_internal(self.pyobj_isolate_old_list)
 
         # For all non-gc pyobjects which have a refcount > 0,
         # mark all reachable objects on the pypy side
@@ -189,6 +179,11 @@
                 next_old = gchdr.c_gc_next
                 found_alive |= self._mark_rawrefcount_obj(gchdr, pyobj_old)
                 gchdr = next_old
+            gchdr = self.pyobj_isolate_old_list.c_gc_next
+            while gchdr <> self.pyobj_isolate_old_list:
+                next_old = gchdr.c_gc_next
+                found_alive |= self._mark_rawrefcount_obj(gchdr, pyobj_old)
+                gchdr = next_old
         #
         # now all rawrefcounted objects, which are alive, have a cyclic
         # refcount > 0 or are marked
diff --git a/rpython/memory/gc/test/dot/keep_finalizer_simple_1b.dot b/rpython/memory/gc/test/dot/keep_finalizer_complex_1.dot
copy from rpython/memory/gc/test/dot/keep_finalizer_simple_1b.dot
copy to rpython/memory/gc/test/dot/keep_finalizer_complex_1.dot
--- a/rpython/memory/gc/test/dot/keep_finalizer_simple_1b.dot
+++ b/rpython/memory/gc/test/dot/keep_finalizer_complex_1.dot
@@ -1,14 +1,14 @@
 digraph G {
-    "a" [type=P, alive=y];
-    "b" [type=B, alive=y];
-    "c" [type=C, alive=y, finalizer=modern, resurrect="c"];
-    "d" [type=C, alive=y];
+    "a" [type=C, alive=n];
+    "b" [type=C, alive=y];
+    "c" [type=B, alive=y];
+    "d" [type=P, alive=y];
     "e" [type=B, alive=y];
-    "f" [type=P, alive=y];
+    "f" [type=C, alive=y, finalizer=modern, resurrect="b"];
     "a" -> "b";
     "b" -> "c";
     "c" -> "d";
     "d" -> "e";
     "e" -> "f";
-    "f" -> "a";
+    "f" -> "f";
 }
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
@@ -776,9 +776,13 @@
             while next <> llmemory.NULL:
                 pyobj = llmemory.cast_adr_to_ptr(next,
                                                  self.gc.rrc_gc.PYOBJ_HDR_PTR)
-                pyobj.c_ob_refcnt += 1
-                finalize_modern(pyobj)
-                decref(pyobj, None)
+                index = self.pyobjs.index(pyobj)
+                if (self.pyobj_finalizer.has_key(index) and
+                        self.pyobj_finalizer[index] ==
+                        RAWREFCOUNT_FINALIZER_MODERN):
+                    pyobj.c_ob_refcnt += 1
+                    finalize_modern(pyobj)
+                    decref(pyobj, None)
                 next = self.gc.rawrefcount_next_cyclic_isolate()
 
             next_dead = self.gc.rawrefcount_cyclic_garbage_head()


More information about the pypy-commit mailing list