Author: Stefan Beyer <[email protected]>
Branch: cpyext-gc-cycle
Changeset: r97191:13bf4458e03a
Date: 2019-08-15 14:28 +0200
http://bitbucket.org/pypy/pypy/changeset/13bf4458e03a/

Log:    Adapted incremental rrc to use snapshot

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
@@ -40,7 +40,7 @@
     _ADDRARRAY = lltype.Array(llmemory.Address, hints={'nolength': True})
     PYOBJ_SNAPSHOT_OBJ = lltype.Struct('PyObject_Snapshot',
                                        ('pyobj', llmemory.Address),
-                                       ('refcnt', lltype.Signed),
+                                       ('status', lltype.Signed),
                                        ('refcnt_external', lltype.Signed),
                                        ('refs_index', lltype.Signed),
                                        ('refs_len', lltype.Signed),
@@ -442,7 +442,6 @@
         else:
             self._free(pyobject, True)
 
-
     def _untrack_tuples(self):
         gchdr = self.tuple_list.c_gc_next
         while gchdr <> self.tuple_list:
@@ -456,136 +455,7 @@
                 self._gc_list_add(self.pyobj_list, gchdr)
             gchdr = gchdr_next
 
-    def _collect_roots(self, pygclist):
-        # Initialize the cyclic refcount with the real refcount.
-        self._collect_roots_init_list(pygclist)
-
-        # Save the real refcount of objects at border
-        self.p_list_old.foreach(self._obj_save_refcnt, None)
-        self.o_list_old.foreach(self._obj_save_refcnt, None)
-
-        # Subtract all internal refcounts from the cyclic refcount
-        # of rawrefcounted objects
-        self._collect_roots_subtract_internal(pygclist)
-
-        # 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, True)
-
-        # For every object in this set, if it is marked, add 1 as a real
-        # refcount (p_list => pyobj stays alive if obj stays alive).
-        self.p_list_old.foreach(self._obj_fix_refcnt, None)
-        self.o_list_old.foreach(self._obj_fix_refcnt, None)
-
-        # now all rawrefcounted roots or live border objects have a
-        # refcount > 0
-        self._debug_check_consistency(print_label="rc-initialized")
-
-    def _collect_roots_init_list(self, pygclist):
-        from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
-        from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
-        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
-            self._pyobj_gc_refcnt_set(pygchdr, refcnt)
-            pygchdr = pygchdr.c_gc_next
-
-    def _collect_roots_subtract_internal(self, pygclist):
-        pygchdr = pygclist.c_gc_next
-        while pygchdr <> pygclist:
-            pyobj = self.gc_as_pyobj(pygchdr)
-            self._traverse(pyobj, -1)
-            pygchdr = pygchdr.c_gc_next
-
-    def _pyobj_gc_refcnt_set(self, pygchdr, refcnt):
-        pygchdr.c_gc_refs &= self.RAWREFCOUNT_REFS_MASK_FINALIZED
-        pygchdr.c_gc_refs |= refcnt << self.RAWREFCOUNT_REFS_SHIFT
-
-    def _obj_save_refcnt(self, pyobject, ignore):
-        pyobj = self._pyobj(pyobject)
-        link = llmemory.cast_int_to_adr(pyobj.c_ob_pypy_link)
-        self.refcnt_dict.setitem(pyobject, link)
-        pyobj.c_ob_pypy_link = pyobj.c_ob_refcnt
-
-    def _obj_fix_refcnt(self, pyobject, ignore):
-        pyobj = self._pyobj(pyobject)
-        #intobj = pyobj.c_ob_pypy_link
-        #obj = llmemory.cast_int_to_adr(intobj)
-        obj = self.refcnt_dict.get(pyobject)
-        gchdr = self.pyobj_as_gc(pyobj)
-        if gchdr <> lltype.nullptr(self.PYOBJ_GC_HDR):
-            rc = gchdr.c_gc_refs
-            refcnt = gchdr.c_gc_refs >> self.RAWREFCOUNT_REFS_SHIFT
-            if rc == self.RAWREFCOUNT_REFS_UNTRACKED:
-                debug_print("gc obj not tracked", gchdr, ": obj", obj,
-                            "cyclic-rc", rc)
-            else:
-                debug_print("gc obj tracked", gchdr, ": obj", obj, "real-rc",
-                            refcnt, "gc-next",
-                            gchdr.c_gc_next, "gc-prev", gchdr.c_gc_prev)
-                if self.gc.header(obj).tid & (self.GCFLAG_VISITED |
-                                              self.GCFLAG_NO_HEAP_PTRS):
-                    refcnt += 1
-                self._pyobj_gc_refcnt_set(gchdr, refcnt)
-
-    def _mark_rawrefcount(self):
-        if self._gc_list_is_empty(self.pyobj_list):
-            self._gc_list_init(self.pyobj_old_list)
-        else:
-            self._gc_list_move(self.pyobj_list, self.pyobj_old_list)
-        # as long as new objects with cyclic a refcount > 0 or alive border
-        # objects are found, increment the refcount of all referenced objects
-        # of those newly found objects
-        found_alive = True
-        pyobj_old = self.pyobj_list
-        #
-        while found_alive: # TODO: working set to improve performance?
-            found_alive = False
-            gchdr = self.pyobj_old_list.c_gc_next
-            while gchdr <> self.pyobj_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
-
-    def _mark_rawrefcount_obj(self, gchdr, gchdr_move):
-        alive = (gchdr.c_gc_refs >> self.RAWREFCOUNT_REFS_SHIFT) > 0
-        pyobj = self.gc_as_pyobj(gchdr)
-        obj = llmemory.NULL
-        if pyobj.c_ob_pypy_link <> 0:
-            #intobj = pyobj.c_ob_pypy_link
-            #obj = llmemory.cast_int_to_adr(intobj)
-            pyobject = llmemory.cast_ptr_to_adr(pyobj)
-            obj = self.refcnt_dict.get(pyobject)
-            if not alive and self.gc.header(obj).tid & (
-                    self.GCFLAG_VISITED | self.GCFLAG_NO_HEAP_PTRS):
-                # add fake refcount, to mark it as live
-                gchdr.c_gc_refs += 1 << self.RAWREFCOUNT_REFS_SHIFT
-                alive = True
-        if alive:
-            # remove from old list
-            next = gchdr.c_gc_next
-            next.c_gc_prev = gchdr.c_gc_prev
-            gchdr.c_gc_prev.c_gc_next = next
-            # add to new list (or not, if it is a tuple)
-            self._gc_list_add(gchdr_move, gchdr)
-            # increment refcounts
-            self._traverse(pyobj, 1)
-            # mark recursively, if it is a pypyobj
-            if pyobj.c_ob_pypy_link <> 0:
-                #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()
-        return alive
-
-    def _find_garbage(self):
+    def _find_garbage(self, use_dict):
         found_garbage = False
         gchdr = self.pyobj_old_list.c_gc_next
         while gchdr <> self.pyobj_old_list:
@@ -593,12 +463,12 @@
             garbage = self.finalizer_type(gchdr) == \
                       self.RAWREFCOUNT_FINALIZER_LEGACY
             if garbage:
-                self._move_to_garbage(gchdr)
+                self._move_to_garbage(gchdr, use_dict)
                 found_garbage = True
             gchdr = next_old
         return found_garbage
 
-    def _mark_garbage(self):
+    def _mark_garbage(self, use_dict):
         found_garbage = True
         #
         while found_garbage:
@@ -609,21 +479,23 @@
                 alive = (gchdr.c_gc_refs >> self.RAWREFCOUNT_REFS_SHIFT) > 0
                 pyobj = self.gc_as_pyobj(gchdr)
                 if pyobj.c_ob_pypy_link <> 0:
-                    #intobj = pyobj.c_ob_pypy_link
-                    #obj = llmemory.cast_int_to_adr(intobj)
-                    pyobject = llmemory.cast_ptr_to_adr(pyobj)
-                    obj = self.refcnt_dict.get(pyobject)
+                    if use_dict:
+                        pyobject = llmemory.cast_ptr_to_adr(pyobj)
+                        obj = self.refcnt_dict.get(pyobject)
+                    else:
+                        intobj = pyobj.c_ob_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):
                         # add fake refcount, to mark it as live
                         gchdr.c_gc_refs += 1 << self.RAWREFCOUNT_REFS_SHIFT
                         alive = True
                 if alive:
-                    self._move_to_garbage(gchdr)
+                    self._move_to_garbage(gchdr, use_dict)
                     found_garbage = True
                 gchdr = next_old
 
-    def _move_to_garbage(self, gchdr):
+    def _move_to_garbage(self, gchdr, use_dict):
         pyobj = self.gc_as_pyobj(gchdr)
         # remove from old list
         next = gchdr.c_gc_next
@@ -642,10 +514,12 @@
         # refcount of zero or an unmarked linked pypy object)
         self._traverse(pyobj, 1)
         if pyobj.c_ob_pypy_link <> 0:
-            #intobj = pyobj.c_ob_pypy_link
-            pyobject = llmemory.cast_ptr_to_adr(pyobj)
-            obj = self.refcnt_dict.get(pyobject)
-            #obj = llmemory.cast_int_to_adr(intobj)
+            if use_dict:
+                pyobject = llmemory.cast_ptr_to_adr(pyobj)
+                obj = self.refcnt_dict.get(pyobject)
+            else:
+                intobj = pyobj.c_ob_pypy_link
+                obj = llmemory.cast_int_to_adr(intobj)
             self.garbage_to_trace.append(obj)
             self.gc.objects_to_trace.append(obj)
             self.gc.visit_all_objects()
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
@@ -55,12 +55,6 @@
             self.state = self.STATE_GARBAGE_MARKING
             return False
 
-        elif self.state == self.STATE_GARBAGE_MARKING:
-            #if self._find_garbage():  # handle legacy finalizers # TODO: from 
snapshot
-            #    self._mark_garbage()  # TODO: from snapshot
-            #    self._debug_check_consistency(print_label="end-legacy-fin")
-            self.state = self.STATE_DEFAULT
-
         # now move all dead objs still in pyob_list to garbage
         # dead -> pyobj_old_list
         # live -> set cyclic refcount to > 0
@@ -81,6 +75,11 @@
                 pygchdr.c_gc_refs = 1 # new object, keep alive
             pygchdr = next_old
 
+        if self._find_garbage(False):  # handle legacy finalizers
+            self._mark_garbage(False)
+            self._debug_check_consistency(print_label="end-legacy-fin")
+        self.state = self.STATE_DEFAULT
+
         # We are finished with marking, now finish things up
         found_finalizer = self._find_finalizer()  # modern finalizers
         if found_finalizer:
@@ -127,7 +126,7 @@
         # refcount > 0 or are marked
 
     def _mark_rawrefcount_obj(self, snapobj):
-        if snapobj.refcnt == 0: # hack
+        if snapobj.status == 0:
             return False
 
         alive = snapobj.refcnt_external > 0
@@ -149,9 +148,8 @@
             if snapobj.pypy_link <> 0:
                 self.gc.objects_to_trace.append(obj)
                 self.gc.visit_all_objects()
-
-            # remove from old list, TODO: hack -> working set might be better
-            snapobj.refcnt = 0
+            # mark as processed
+            snapobj.status = 0
         return alive
 
     def _take_snapshot(self, pygclist):
@@ -196,7 +194,7 @@
             pygchdr.c_gc_refs = objs_index + 1
             obj = self.snapshot_objs[objs_index]
             obj.pyobj = llmemory.cast_ptr_to_adr(pyobj)
-            obj.refcnt = 1
+            obj.status = 1
             obj.refcnt_external = refcnt
             obj.refs_index = refs_index
             obj.refs_len = 0
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
@@ -1,4 +1,5 @@
 from rpython.memory.gc.rrc.base import RawRefCountBaseGC
+from rpython.rtyper.lltypesystem import lltype, llmemory, llgroup, rffi
 from rpython.rlib.debug import ll_assert, debug_print, debug_start, debug_stop
 
 class RawRefCountMarkGC(RawRefCountBaseGC):
@@ -35,8 +36,8 @@
             self._mark_rawrefcount()
             self._debug_check_consistency(print_label="before-fin")
             self.state = self.STATE_GARBAGE_MARKING
-            if self._find_garbage(): # handle legacy finalizers
-                self._mark_garbage()
+            if self._find_garbage(True): # handle legacy finalizers
+                self._mark_garbage(True)
                 self._debug_check_consistency(print_label="end-legacy-fin")
             self.state = self.STATE_MARKING
             found_finalizer = self._find_finalizer()
@@ -60,3 +61,132 @@
 
         self.state = self.STATE_DEFAULT
         return True
+
+    def _collect_roots(self, pygclist):
+        # Initialize the cyclic refcount with the real refcount.
+        self._collect_roots_init_list(pygclist)
+
+        # Save the real refcount of objects at border
+        self.p_list_old.foreach(self._obj_save_refcnt, None)
+        self.o_list_old.foreach(self._obj_save_refcnt, None)
+
+        # Subtract all internal refcounts from the cyclic refcount
+        # of rawrefcounted objects
+        self._collect_roots_subtract_internal(pygclist)
+
+        # 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, True)
+
+        # For every object in this set, if it is marked, add 1 as a real
+        # refcount (p_list => pyobj stays alive if obj stays alive).
+        self.p_list_old.foreach(self._obj_fix_refcnt, None)
+        self.o_list_old.foreach(self._obj_fix_refcnt, None)
+
+        # now all rawrefcounted roots or live border objects have a
+        # refcount > 0
+        self._debug_check_consistency(print_label="rc-initialized")
+
+    def _collect_roots_init_list(self, pygclist):
+        from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
+        from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
+        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
+            self._pyobj_gc_refcnt_set(pygchdr, refcnt)
+            pygchdr = pygchdr.c_gc_next
+
+    def _collect_roots_subtract_internal(self, pygclist):
+        pygchdr = pygclist.c_gc_next
+        while pygchdr <> pygclist:
+            pyobj = self.gc_as_pyobj(pygchdr)
+            self._traverse(pyobj, -1)
+            pygchdr = pygchdr.c_gc_next
+
+    def _pyobj_gc_refcnt_set(self, pygchdr, refcnt):
+        pygchdr.c_gc_refs &= self.RAWREFCOUNT_REFS_MASK_FINALIZED
+        pygchdr.c_gc_refs |= refcnt << self.RAWREFCOUNT_REFS_SHIFT
+
+    def _obj_save_refcnt(self, pyobject, ignore):
+        pyobj = self._pyobj(pyobject)
+        link = llmemory.cast_int_to_adr(pyobj.c_ob_pypy_link)
+        self.refcnt_dict.setitem(pyobject, link)
+        pyobj.c_ob_pypy_link = pyobj.c_ob_refcnt
+
+    def _obj_fix_refcnt(self, pyobject, ignore):
+        pyobj = self._pyobj(pyobject)
+        #intobj = pyobj.c_ob_pypy_link
+        #obj = llmemory.cast_int_to_adr(intobj)
+        obj = self.refcnt_dict.get(pyobject)
+        gchdr = self.pyobj_as_gc(pyobj)
+        if gchdr <> lltype.nullptr(self.PYOBJ_GC_HDR):
+            rc = gchdr.c_gc_refs
+            refcnt = gchdr.c_gc_refs >> self.RAWREFCOUNT_REFS_SHIFT
+            if rc == self.RAWREFCOUNT_REFS_UNTRACKED:
+                debug_print("gc obj not tracked", gchdr, ": obj", obj,
+                            "cyclic-rc", rc)
+            else:
+                debug_print("gc obj tracked", gchdr, ": obj", obj, "real-rc",
+                            refcnt, "gc-next",
+                            gchdr.c_gc_next, "gc-prev", gchdr.c_gc_prev)
+                if self.gc.header(obj).tid & (self.GCFLAG_VISITED |
+                                              self.GCFLAG_NO_HEAP_PTRS):
+                    refcnt += 1
+                self._pyobj_gc_refcnt_set(gchdr, refcnt)
+
+    def _mark_rawrefcount(self):
+        if self._gc_list_is_empty(self.pyobj_list):
+            self._gc_list_init(self.pyobj_old_list)
+        else:
+            self._gc_list_move(self.pyobj_list, self.pyobj_old_list)
+        # as long as new objects with cyclic a refcount > 0 or alive border
+        # objects are found, increment the refcount of all referenced objects
+        # of those newly found objects
+        found_alive = True
+        pyobj_old = self.pyobj_list
+        #
+        while found_alive: # TODO: working set to improve performance?
+            found_alive = False
+            gchdr = self.pyobj_old_list.c_gc_next
+            while gchdr <> self.pyobj_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
+
+    def _mark_rawrefcount_obj(self, gchdr, gchdr_move):
+        alive = (gchdr.c_gc_refs >> self.RAWREFCOUNT_REFS_SHIFT) > 0
+        pyobj = self.gc_as_pyobj(gchdr)
+        obj = llmemory.NULL
+        if pyobj.c_ob_pypy_link <> 0:
+            #intobj = pyobj.c_ob_pypy_link
+            #obj = llmemory.cast_int_to_adr(intobj)
+            pyobject = llmemory.cast_ptr_to_adr(pyobj)
+            obj = self.refcnt_dict.get(pyobject)
+            if not alive and self.gc.header(obj).tid & (
+                    self.GCFLAG_VISITED | self.GCFLAG_NO_HEAP_PTRS):
+                # add fake refcount, to mark it as live
+                gchdr.c_gc_refs += 1 << self.RAWREFCOUNT_REFS_SHIFT
+                alive = True
+        if alive:
+            # remove from old list
+            next = gchdr.c_gc_next
+            next.c_gc_prev = gchdr.c_gc_prev
+            gchdr.c_gc_prev.c_gc_next = next
+            # add to new list (or not, if it is a tuple)
+            self._gc_list_add(gchdr_move, gchdr)
+            # increment refcounts
+            self._traverse(pyobj, 1)
+            # mark recursively, if it is a pypyobj
+            if pyobj.c_ob_pypy_link <> 0:
+                #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()
+        return alive
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to