[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