Author: Stefan Beyer <[email protected]>
Branch: cpyext-gc-cycle
Changeset: r97553:73cc4bd3f3ca
Date: 2019-09-19 10:25 +0200
http://bitbucket.org/pypy/pypy/changeset/73cc4bd3f3ca/
Log: Include p_list in snapshot of rrc incmark Fixed some other issues
and added some TODOs
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
@@ -41,8 +41,8 @@
PYOBJ_SNAPSHOT_OBJ = lltype.Struct('PyObject_Snapshot',
('pyobj', llmemory.Address),
('status', lltype.Signed),
+ ('refcnt_original', lltype.Signed),
('refcnt', lltype.Signed),
- ('refcnt_external', lltype.Signed),
('refs_index', lltype.Signed),
('refs_len', lltype.Signed),
('pypy_link', lltype.Signed))
@@ -345,6 +345,7 @@
def _major_trace(self, pyobject, flags):
from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
+ # TODO: add flag; if set: if marked, keep rc-proxy
(use_cylicrefcnt, use_dict) = flags
#
pyobj = self._pyobj(pyobject)
@@ -360,7 +361,10 @@
else:
rc = pyobj.c_ob_refcnt
else:
- rc = pyobj.c_ob_refcnt
+ if use_dict:
+ rc = pyobj.c_ob_pypy_link
+ else:
+ rc = pyobj.c_ob_refcnt
if rc == REFCNT_FROM_PYPY or rc == REFCNT_FROM_PYPY_LIGHT or rc == 0:
pass # the corresponding object may die
@@ -374,7 +378,7 @@
intobj = pyobj.c_ob_pypy_link
obj = llmemory.cast_int_to_adr(intobj)
self.gc.objects_to_trace.append(obj)
- self.gc.visit_all_objects()
+ self.gc.visit_all_objects() # TODO: execute incrementally?
def _major_trace_nongc(self, pyobject, use_dict):
from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
@@ -416,8 +420,7 @@
self.p_dict = new_p_dict = self.gc.AddressDict(length_estimate)
new_p_list = self.gc.AddressStack()
while self.p_list_old.non_empty():
- self._major_free(self.p_list_old.pop(), new_p_list,
- new_p_dict)
+ self._major_free(self.p_list_old.pop(), new_p_list, new_p_dict)
self.p_list_old.delete()
self.p_list_old = new_p_list
#
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
@@ -59,8 +59,8 @@
# all objects have been marked, dead objects will stay dead
self._debug_check_consistency(print_label="before-fin")
self.state = self.STATE_GARBAGE_MARKING
-
- return False
+ else:
+ return False
# we are finished with marking, now finish things up
ll_assert(self.state == self.STATE_GARBAGE_MARKING, "invalid state")
@@ -75,16 +75,16 @@
pygchdr = self.pyobj_list.c_gc_next
consistent = True
self.snapshot_consistent = True
- while pygchdr <> self.pyobj_list:
+ while pygchdr <> self.pyobj_list: # TODO: also sync p_list
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_external
- if snapobj.refcnt_external == 0: # object considered dead
+ 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 == pyobj.c_ob_refcnt
+ consistent = snapobj.refcnt_original == pyobj.c_ob_refcnt
if not consistent:
break
# outgoing (internal) references equal
@@ -99,6 +99,7 @@
self._gc_list_add(self.pyobj_old_list, pygchdr)
else:
pygchdr.c_gc_refs = 1 # new object, keep alive
+ # TODO: also keep reachable objects alive (in case rc proxy ->
non-rc -> non-rc proxy -> rc obj!!!)
pygchdr = next_old
self._debug_check_consistency(print_label="end-check-consistency")
@@ -148,7 +149,7 @@
addr = self.snapshot_refs[obj.refs_index + j]
obj_ref = llmemory.cast_adr_to_ptr(addr,
self.PYOBJ_SNAPSHOT_OBJ_PTR)
- obj_ref.refcnt_external -= 1
+ obj_ref.refcnt -= 1
# now all rawrefcounted roots or live border objects have a
# refcount > 0
@@ -176,21 +177,21 @@
if snapobj.status == 0: # already processed
return False
- alive = snapobj.refcnt_external > 0
+ alive = snapobj.refcnt > 0
if snapobj.pypy_link <> 0:
intobj = snapobj.pypy_link
obj = llmemory.cast_int_to_adr(intobj)
if not alive and self.gc.header(obj).tid & (
self.GCFLAG_VISITED | self.GCFLAG_NO_HEAP_PTRS):
alive = True
- snapobj.refcnt_external += 1
+ snapobj.refcnt += 1
if alive:
# increment refcounts
for j in range(0, snapobj.refs_len):
addr = self.snapshot_refs[snapobj.refs_index + j]
obj_ref = llmemory.cast_adr_to_ptr(addr,
self.PYOBJ_SNAPSHOT_OBJ_PTR)
- obj_ref.refcnt_external += 1
+ obj_ref.refcnt += 1
# mark recursively, if it is a pypyobj
if snapobj.pypy_link <> 0:
intobj = snapobj.pypy_link
@@ -204,7 +205,8 @@
def _take_snapshot(self, pygclist):
from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
- #
+
+ # calculate size of memory buffer for snapshot
total_refcnt = 0
total_objs = 0
pygchdr = pygclist.c_gc_next
@@ -217,6 +219,13 @@
total_refcnt += refcnt
total_objs += 1
pygchdr = pygchdr.c_gc_next
+ self.p_list_count = 0
+ self.p_list_refcnt = 0
+ self.p_list_old.foreach(self._take_snapshot_count, None)
+ total_objs += self.p_list_count
+ total_refcnt += self.p_list_refcnt
+
+ # initialize memory
self.snapshot_refs = lltype.malloc(self._ADDRARRAY, total_refcnt,
flavor='raw',
track_allocation=False)
@@ -224,9 +233,13 @@
flavor='raw',
track_allocation=False)
self.total_objs = total_objs
+ self.objs_index = 0
+ self.refs_index = 0
- objs_index = 0
- refs_index = 0
+ # take snapshot of p_list_old
+ self.p_list_old.foreach(self._take_snapshot_pyobject, None)
+
+ # take snapshot of gc objs
pygchdr = pygclist.c_gc_next
while pygchdr <> pygclist:
pyobj = self.gc_as_pyobj(pygchdr)
@@ -240,26 +253,93 @@
if self.gc.header(addr).tid & (self.GCFLAG_VISITED |
self.GCFLAG_NO_HEAP_PTRS):
refcnt += 1
- pygchdr.c_gc_refs = objs_index + 1
- obj = self.snapshot_objs[objs_index]
+ 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 = pyobj.c_ob_refcnt
- obj.refcnt_external = refcnt
- obj.refs_index = refs_index
+ 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)
- objs_index += 1
- refs_index += obj.refs_len
+ self.objs_index += 1
+ self.refs_index += obj.refs_len
pygchdr = pygchdr.c_gc_next
- for i in range(0, refs_index):
+
+ # fix references
+ for i in range(0, self.refs_index):
addr = self.snapshot_refs[i]
- pyobj = llmemory.cast_adr_to_ptr(addr, self.PYOBJ_GC_HDR_PTR)
- obj = self.snapshot_objs[pyobj.c_gc_refs - 1]
+ pyobj = llmemory.cast_adr_to_ptr(addr, 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):
+ obj = self.snapshot_objs[pygchdr.c_gc_refs - 1]
+ else:
+ obj = self.snapshot_objs[pyobj.c_ob_pypy_link - 1]
self.snapshot_refs[i] = llmemory.cast_ptr_to_adr(obj)
+ # fix links of p_list_old back
+ self.p_list_old.foreach(self._take_snapshot_fixlink, None)
+
+ def _take_snapshot_count(self, pyobject, foo):
+ from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
+ from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
+ #
+ pyobj = self._pyobj(pyobject)
+ pygchdr = self.pyobj_as_gc(pyobj)
+ # only include non-gc
+ if (pygchdr == lltype.nullptr(self.PYOBJ_GC_HDR) or
+ pygchdr.c_gc_refs == self.RAWREFCOUNT_REFS_UNTRACKED):
+ self.p_list_count += 1
+ 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
+ self.p_list_refcnt += refcnt
+
+ def _take_snapshot_pyobject(self, pyobject, foo):
+ from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
+ from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
+ #
+ pyobj = self._pyobj(pyobject)
+ pygchdr = self.pyobj_as_gc(pyobj)
+ # only include non-gc
+ if (pygchdr == lltype.nullptr(self.PYOBJ_GC_HDR) or
+ pygchdr.c_gc_refs == self.RAWREFCOUNT_REFS_UNTRACKED):
+ 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
+ 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 = 0
+ obj.refs_len = 0
+ obj.pypy_link = pyobj.c_ob_pypy_link
+ pyobj.c_ob_pypy_link = self.objs_index + 1
+ self.objs_index += 1
+
+ def _take_snapshot_fixlink(self, pyobject, foo):
+ pyobj = self._pyobj(pyobject)
+ pygchdr = self.pyobj_as_gc(pyobj)
+ # only include non-gc
+ if (pygchdr == lltype.nullptr(self.PYOBJ_GC_HDR) or
+ pygchdr.c_gc_refs == self.RAWREFCOUNT_REFS_UNTRACKED):
+ obj_index = pyobj.c_ob_pypy_link - 1
+ obj = self.snapshot_objs[obj_index]
+ pyobj.c_ob_pypy_link = obj.pypy_link
+
def _take_snapshot_visit(pyobj, self_ptr):
from rpython.rtyper.annlowlevel import cast_adr_to_nongc_instance
#
@@ -270,11 +350,12 @@
def _take_snapshot_visit_action(self, pyobj, ignore):
pygchdr = self.pyobj_as_gc(pyobj)
- if pygchdr <> lltype.nullptr(self.PYOBJ_GC_HDR) and \
- pygchdr.c_gc_refs != self.RAWREFCOUNT_REFS_UNTRACKED:
- curr = self.snapshot_curr
- index = curr.refs_index + curr.refs_len
- self.snapshot_refs[index] = llmemory.cast_ptr_to_adr(pygchdr)
+ curr = self.snapshot_curr
+ index = curr.refs_index + curr.refs_len
+ if ((pygchdr <> lltype.nullptr(self.PYOBJ_GC_HDR) and
+ pygchdr.c_gc_refs != self.RAWREFCOUNT_REFS_UNTRACKED) or
+ pyobj.c_ob_pypy_link != 0):
+ self.snapshot_refs[index] = llmemory.cast_ptr_to_adr(pyobj)
curr.refs_len += 1
def _take_snapshot_traverse(self, pyobj):
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
@@ -60,19 +60,21 @@
self.pyobj_isolate_list)
use_cylicrc = not found_finalizer
self._debug_check_consistency(print_label="end-mark-cyclic")
+
+ # mark all pypy objects at the border which are linked to non-gc
+ # pyobjs which are not directly referenced by any gc pyobj
+ debug_print("use_cylicrc", use_cylicrc)
+ self.p_list_old.foreach(self._major_trace, (use_cylicrc, True)) #
TODO: set flag to keep marked, check other occurences
+ self._debug_check_consistency(print_label="end-mark")
+
+ # fix refcnt back
+ self.refcnt_dict.foreach(self._fix_refcnt_back, None)
+ self.refcnt_dict.delete()
+ self.refcnt_dict = self.gc.AddressDict()
+ self.use_refcntdict = False
else:
- use_cylicrc = False # don't sweep any objects in cyclic isolates
-
- # now mark all pypy objects at the border, depending on the results
- debug_print("use_cylicrc", use_cylicrc)
- self.p_list_old.foreach(self._major_trace, (use_cylicrc, True))
- self._debug_check_consistency(print_label="end-mark")
-
- # fix refcnt back
- self.refcnt_dict.foreach(self._fix_refcnt_back, None)
- self.refcnt_dict.delete()
- self.refcnt_dict = self.gc.AddressDict()
- self.use_refcntdict = False
+ self.p_list_old.foreach(self._major_trace, (False, False)) #
TODO: set flag to keep marked, check other occurences
+ self._debug_check_consistency(print_label="end-mark")
self.state = self.STATE_DEFAULT
return True
@@ -89,7 +91,11 @@
# Initialize the cyclic refcount with the real refcount.
self._collect_roots_init_list(self.pyobj_list)
- # Save the real refcount of objects at border
+ # 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
+ # rrc side, so we need to store their cyclic refcount somewhere else;
+ # we choose the pypy_link field and use a dict to lookup the pypy_link,
+ # if necessary)
self.p_list_old.foreach(self._obj_save_refcnt, None)
self.o_list_old.foreach(self._obj_save_refcnt, None)
self.use_refcntdict = True
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit