Author: Armin Rigo <[email protected]>
Branch: gc-forkfriendly-2
Changeset: r90324:fe4764a96a25
Date: 2017-02-23 15:34 +0100
http://bitbucket.org/pypy/pypy/changeset/fe4764a96a25/

Log:    in-progress: try to identify all the GCFLAG_VISITED checks on
        potentially minimarkpaged-objects

diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -113,6 +113,9 @@
 GCFLAG_NO_HEAP_PTRS = first_gcflag << 1
 
 # The following flag is set on surviving objects during a major collection.
+# However, if 'offline_visited_flags' is True, then it is never set on
+# objects in the minimarkpage arenas; instead, we use an offline set of
+# flags.  See get_visited().
 GCFLAG_VISITED      = first_gcflag << 2
 
 # The following flag is set on nursery objects of which we asked the id
@@ -285,6 +288,7 @@
                  card_page_indices=0,
                  large_object=8*WORD,
                  ArenaCollectionClass=None,
+                 offline_visited_flags=False,
                  **kwds):
         "NOT_RPYTHON"
         MovingGCBase.__init__(self, config, **kwds)
@@ -311,6 +315,7 @@
         # 'large_object' limit how big objects can be in the nursery, so
         # it gives a lower bound on the allowed size of the nursery.
         self.nonlarge_max = large_object - 1
+        self.offline_visited_flags = offline_visited_flags
         #
         self.nursery      = llmemory.NULL
         self.nursery_free = llmemory.NULL
@@ -1211,6 +1216,64 @@
             ((r_uint(length) + r_uint((8 << self.card_page_shift) - 1)) >>
              (self.card_page_shift + 3)))
 
+    def get_visited(self, obj):
+        # Return the value of the object's GCFLAG_VISITED flag, noting
+        # that it may be stored offline.  This assumes that 'obj' is an
+        # old object.
+        tid = self.header(obj).tid
+        if self.offline_visited_flags:
+            if tid & GCFLAG_OLD_OUTSIDE_MINIMARKPAGE == 0:
+                ll_assert((tid & GCFLAG_VISITED) == 0,
+                          "minimarkpage object with in-line GCFLAG_VISITED 
set")
+                return self.ac.get_visited(obj)
+        return tid & GCFLAG_VISITED != 0
+
+    @specialize.arg(2)
+    def get_visited_or_other_flag(self, obj, other_flag):
+        # Returns 'get_visited(obj) or (tid & other_flag != 0)'
+        # (optimized version)
+        tid = self.header(obj).tid
+        if self.offline_visited_flags:
+            ll_assert(tid & (GCFLAG_OLD_OUTSIDE_MINIMARKPAGE | GCFLAG_VISITED)
+                      != GCFLAG_VISITED, "minimarkpage object with in-line "
+                                         "GCFLAG_VISITED set /2")
+            if (tid & (GCFLAG_OLD_OUTSIDE_MINIMARKPAGE | other_flag)) == 0:
+                return self.ac.get_visited(obj)
+        return (tid & (GCFLAG_VISITED | other_flag)) != 0
+
+    def set_visited(self, obj):
+        # Set the object's GCFLAG_VISITED flag, noting that it may be
+        # stored offline.  This assumes that 'obj' is an old object.
+        tid = self.header(obj).tid
+        if self.offline_visited_flags:
+            if tid & GCFLAG_OLD_OUTSIDE_MINIMARKPAGE == 0:
+                self.ac.set_visited(obj)
+                return
+        self.header(obj).tid = tid | GCFLAG_VISITED
+
+    @specialize.arg(2)
+    def set_visited_and_other_flag(self, obj, other_flag):
+        # Optimized 'set_visited(obj)' followed by setting 'other_flag' too
+        tid = self.header(obj).tid | other_flag
+        must_set_gcflag_visited = True
+        if self.offline_visited_flags:
+            if tid & GCFLAG_OLD_OUTSIDE_MINIMARKPAGE == 0:
+                self.ac.set_visited(obj)
+                must_set_gcflag_visited = False
+        if must_set_gcflag_visited:
+            tid |= GCFLAG_VISITED
+        self.header(obj).tid = tid
+
+    def clear_visited(self, obj):
+        # Clear the object's GCFLAG_VISITED flag, noting that it may be
+        # stored offline.  This assumes that 'obj' is an old object.
+        tid = self.header(obj).tid
+        if self.offline_visited_flags:
+            if tid & GCFLAG_OLD_OUTSIDE_MINIMARKPAGE == 0:
+                self.ac.clear_visited(obj)
+                return
+        self.header(obj).tid = tid & ~GCFLAG_VISITED
+
     def debug_check_consistency(self):
         if self.DEBUG:
             ll_assert(not self.young_rawmalloced_objects,
@@ -1275,7 +1338,7 @@
             ll_assert(False, "unknown gc_state value")
 
     def _debug_check_object_marking(self, obj):
-        if self.header(obj).tid & GCFLAG_VISITED != 0:
+        if self.get_visited(obj):
             # A black object.  Should NEVER point to a white object.
             self.trace(obj, self._debug_check_not_white, None)
             # During marking, all visited (black) objects should always have
@@ -1290,7 +1353,7 @@
 
     def _debug_check_not_white(self, root, ignored):
         obj = root.address[0]
-        if self.header(obj).tid & GCFLAG_VISITED != 0:
+        if self.get_visited(obj):
             pass    # black -> black
         elif (self._debug_objects_to_trace_dict1.contains(obj) or
               self._debug_objects_to_trace_dict2.contains(obj)):
@@ -1355,6 +1418,7 @@
         # the GCFLAG_VISITED should not be set between collections
         ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0,
                   "unexpected GCFLAG_VISITED")
+        ll_assert(not self.get_visited(obj), "unexpected off-line visited")
 
         # All other invariants from the sweeping phase should still be
         # satisfied.
@@ -1616,7 +1680,7 @@
             # visit shadow to keep it alive
             # XXX seems like it is save to set GCFLAG_VISITED, however
             # should be double checked
-            self.header(shadow).tid |= GCFLAG_VISITED
+            self.set_visited(shadow)
             new_shadow_object_dict.setitem(obj, shadow)
 
     def register_finalizer(self, fq_index, gcobj):
@@ -1787,6 +1851,8 @@
             #
             # clean up object's flags
             obj = cur + size_gc_header
+            ll_assert((self.header(obj).tid & GCFLAG_OLD_OUTSIDE_MINIMARKPAGE)
+                      != 0, "pinned obj: !old_outside_minimarkpage")
             self.header(obj).tid &= ~GCFLAG_VISITED
             #
             # create a new nursery barrier for the pinned object
@@ -1927,7 +1993,7 @@
                 ll_assert(not self.is_in_nursery(obj),
                           "expected nursery obj in 
collect_cardrefs_to_nursery")
                 if self.gc_state == STATE_MARKING:
-                    self.header(obj).tid &= ~GCFLAG_VISITED
+                    self.clear_visited(obj)
                     self.more_objects_to_trace.append(obj)
 
 
@@ -1986,7 +2052,7 @@
         # Additionally, ignore pinned objects.
         #
         obj = root.address[0]
-        if (self.header(obj).tid & (GCFLAG_VISITED | GCFLAG_PINNED)) == 0:
+        if not self.get_visited_or_other_flag(obj, GCFLAG_PINNED):
             self.more_objects_to_trace.append(obj)
 
     def _trace_drag_out(self, root, parent):
@@ -2197,11 +2263,11 @@
 
     def _add_to_more_objects_to_trace(self, obj, ignored):
         ll_assert(not self.is_in_nursery(obj), "unexpected nursery obj here")
-        self.header(obj).tid &= ~GCFLAG_VISITED
+        self.clear_visited(obj)
         self.more_objects_to_trace.append(obj)
 
     def _add_to_more_objects_to_trace_if_black(self, obj, ignored):
-        if self.header(obj).tid & GCFLAG_VISITED:
+        if self.get_visited(obj):
             self._add_to_more_objects_to_trace(obj, ignored)
 
     def minor_and_major_collection(self):
@@ -2444,7 +2510,7 @@
         debug_stop("gc-collect-step")
 
     def _sweep_old_objects_pointing_to_pinned(self, obj, new_list):
-        if self.header(obj).tid & GCFLAG_VISITED:
+        if self.get_visited(obj):
             new_list.append(obj)
 
     def _free_if_unvisited(self, hdr):
@@ -2592,12 +2658,12 @@
                   "pinned object in 'objects_to_trace'")
         ll_assert(not self.is_in_nursery(obj),
                   "nursery object in 'objects_to_trace'")
-        if hdr.tid & (GCFLAG_VISITED | GCFLAG_NO_HEAP_PTRS):
+        if self.get_visited_or_other_flag(obj, GCFLAG_NO_HEAP_PTRS):
             return 0
         #
         # It's the first time.  We set the flag VISITED.  The trick is
         # to also set TRACK_YOUNG_PTRS here, for the write barrier.
-        hdr.tid |= GCFLAG_VISITED | GCFLAG_TRACK_YOUNG_PTRS
+        self.set_visited_and_other_flag(obj, GCFLAG_TRACK_YOUNG_PTRS)
 
         if self.has_gcptr(llop.extract_ushort(llgroup.HALFWORD, hdr.tid)):
             #
@@ -2705,7 +2771,7 @@
         new_objects = self.AddressStack()
         while self.old_objects_with_destructors.non_empty():
             obj = self.old_objects_with_destructors.pop()
-            if self.header(obj).tid & GCFLAG_VISITED:
+            if self.get_visited(obj):
                 # surviving
                 new_objects.append(obj)
             else:
@@ -2744,7 +2810,7 @@
                       "bad finalization state 1")
             if self.header(x).tid & GCFLAG_IGNORE_FINALIZER:
                 continue
-            if self.header(x).tid & GCFLAG_VISITED:
+            if self.get_visited(x):
                 new_with_finalizer.append(x)
                 new_with_finalizer.append(fq_nr)
                 continue
@@ -2796,7 +2862,7 @@
 
     def _finalization_state(self, obj):
         tid = self.header(obj).tid
-        if tid & GCFLAG_VISITED:
+        if self.get_visited(obj):
             if tid & GCFLAG_FINALIZATION_ORDERING:
                 return 2
             else:
@@ -2904,7 +2970,7 @@
         new_with_weakref = self.AddressStack()
         while self.old_objects_with_weakrefs.non_empty():
             obj = self.old_objects_with_weakrefs.pop()
-            if self.header(obj).tid & GCFLAG_VISITED == 0:
+            if not self.get_visited(obj):
                 continue # weakref itself dies
             offset = self.weakpointer_offset(self.get_type_id(obj))
             pointing_to = (obj + offset).address[0]
@@ -2912,8 +2978,8 @@
                       == 0, "registered old weakref should not "
                             "point to a NO_HEAP_PTRS obj")
             tid = self.header(pointing_to).tid
-            if ((tid & (GCFLAG_VISITED | GCFLAG_FINALIZATION_ORDERING)) ==
-                        GCFLAG_VISITED):
+            if (self.get_visited(pointing_to) and
+                    tid & GCFLAG_FINALIZATION_ORDERING == 0):
                 new_with_weakref.append(obj)
             else:
                 (obj + offset).address[0] = llmemory.NULL
@@ -3160,7 +3226,7 @@
         #  * GCFLAG_NO_HEAP_PTRS: immortal object never traced (so far)
         intobj = self._pyobj(pyobject).ob_pypy_link
         obj = llmemory.cast_int_to_adr(intobj)
-        if self.header(obj).tid & (GCFLAG_VISITED | GCFLAG_NO_HEAP_PTRS):
+        if self.get_visited_or_other_flag(obj, GCFLAG_NO_HEAP_PTRS):
             surviving_list.append(pyobject)
             if surviving_dict:
                 surviving_dict.insertclean(obj, pyobject)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to