Author: Armin Rigo <[email protected]>
Branch: gc-del
Changeset: r62804:0c3d7f55af78
Date: 2013-03-26 13:52 +0100
http://bitbucket.org/pypy/pypy/changeset/0c3d7f55af78/

Log:    Found out a simpler solution.

diff --git a/rpython/memory/gc/minimark.py b/rpython/memory/gc/minimark.py
--- a/rpython/memory/gc/minimark.py
+++ b/rpython/memory/gc/minimark.py
@@ -1243,7 +1243,6 @@
         #
         # Before everything else, remove from 'old_objects_pointing_to_young'
         # the young arrays.
-        self.remember_young_rawmalloced_visited = None
         if self.young_rawmalloced_objects:
             self.remove_young_arrays_from_old_objects_pointing_to_young()
         #
@@ -1370,6 +1369,7 @@
     def collect_oldrefs_to_nursery(self):
         # Follow the old_objects_pointing_to_young list and move the
         # young objects they point to out of the nursery.
+        self.record_duplicates = False
         oldlist = self.old_objects_pointing_to_young
         while True:
             if oldlist.non_empty():
@@ -1402,6 +1402,9 @@
                     # Both 'old_objects_pointing_to_young' and
                     # 'old_objects_with_cards_set' are now empty: done
                     break
+        #
+        if not we_are_translated():
+            del self.record_duplicates
 
 
     def trace_and_drag_out_of_nursery(self, obj):
@@ -1454,7 +1457,13 @@
             #
             # 'obj' was already forwarded.  Change the original reference
             # to point to its forwarding address, and we're done.
-            root.address[0] = self.get_forwarding_address(obj)
+            newobj = self.get_forwarding_address(obj)
+            root.address[0] = newobj
+            #
+            # Avoid the following useless append(), unless we are tracing
+            # from dying objects with finalizers
+            if self.record_duplicates:
+                self.old_objects_pointing_to_young.append(newobj)
             return
             #
         else:
@@ -1493,7 +1502,7 @@
         # We will fix such references to point to the copy of the young
         # objects when we walk 'old_objects_pointing_to_young'.
         self.old_objects_pointing_to_young.append(newobj)
-        debug_print("adding", newobj)
+        #debug_print("adding", newobj)
     _trace_drag_out._always_inline_ = True
 
     def _visit_young_rawmalloced_object(self, obj):
@@ -1523,10 +1532,6 @@
             added_somewhere = True
         #
         ll_assert(added_somewhere, "wrong flag combination on young array")
-        #
-        # If 'remember_young_rawmalloced_visited', record it there as well
-        if self.remember_young_rawmalloced_visited:
-            self.remember_young_rawmalloced_visited.append(obj)
 
 
     def _malloc_out_of_nursery(self, totalsize):
@@ -1927,75 +1932,88 @@
         objects with finalizers.  As these survive for a bit longer,
         we also need to copy them out of the nursery.  The tricky part
         here is to enqueue them in topological order, if possible.
-
-        This is done as three steps: first we find which objects are
-        not reachable at all from 'outside'; then we copy them outside
-        the nursery together with everything they point to; and finally
-        we use on them the generic _deal_with_objects_with_finalizers().
         """
         ll_assert(not self.old_objects_pointing_to_young.non_empty(),
                   "deal_with_young_objects_with_finalizers: "
                   "old_objects_pointing_to_young should be empty")
-        ll_assert(not self.objects_to_trace.non_empty(),
-                  "objects_to_trace non empty [deal_young_finalizer]")
         finalizer_funcs = self.AddressDict()
+        self.finalizers_scheduled = self.AddressStack()
+        self.record_duplicates = True
         #
         while self.young_objects_with_finalizers.non_empty():
             func = self.young_objects_with_finalizers.pop()
             obj = self.young_objects_with_finalizers.pop()
             #
-            survives = False
+            # The following lines move 'obj' out of the nursery and add it to
+            # 'self.old_objects_pointing_to_young' --- unless the object
+            # survive, in which case it was already seen and the following
+            # lines have no effect.
+            root = self.temp_root
+            root.address[0] = obj
+            self._trace_drag_out1(root)
+            objcopy = root.address[0]
+            #debug_print("finalizer for", obj)
+            #debug_print("object moving to", objcopy)
             #
-            if self.is_in_nursery(obj):
-                if self.is_forwarded(obj):
-                    obj = self.get_forwarding_address(obj)
-                    survives = True
-                else:
-                    #
-                    # The following lines move 'obj' out of the nursery and
-                    # add it to 'self.old_objects_pointing_to_young'.
-                    root = self.temp_root
-                    root.address[0] = obj
-                    self._trace_drag_out1(root)
-                    obj = root.address[0]
+            # Remember the finalizer in the dict
+            finalizer_funcs.setitem(objcopy, func)
             #
-            elif (bool(self.young_rawmalloced_objects) and
-                  self.young_rawmalloced_objects.contains(obj)):
-                if self.header(obj).tid & GCFLAG_VISITED:
-                    survives = True
-            #
-            if survives:
-                self.old_objects_with_finalizers.append(obj)
-                self.old_objects_with_finalizers.append(func)
+            # Now follow all the refs
+            self._follow_references_from_young_object_with_finalizer()
+        #
+        if not we_are_translated():
+            del self.record_duplicates
+        #
+        # Copy the objects scheduled into 'run_finalizers_queue', in
+        # reverse order.
+        while self.finalizers_scheduled.non_empty():
+            obj = self.finalizers_scheduled.pop()
+            func = finalizer_funcs.get(obj)
+            ll_assert(func != NULL, "lost finalizer [1]")
+            self.run_finalizers_queue.append(obj)
+            self.run_finalizers_funcs.append(func)
+            finalizer_funcs.setitem(obj, NULL)
+        self.finalizers_scheduled.delete()
+        #
+        # The non-NULL entries remaining in 'finalizer_funcs' correspond
+        # to objects that survived, because they have not been traced by
+        # this function but already before.
+        finalizer_funcs.foreach(self._move_to_old_finalizer,
+                                self.old_objects_with_finalizers)
+        finalizer_funcs.delete()
+
+    def _follow_references_from_young_object_with_finalizer(self):
+        pending = self.old_objects_pointing_to_young
+        while pending.non_empty():
+            assert not self.old_objects_with_cards_set.non_empty(), "XXX"
+            obj = pending.pop()
+            #debug_print("popping", obj)
+            if obj:
+                #
+                if self.header(obj).tid & GCFLAG_HAS_FINALIZER:
+                    self.header(obj).tid &= ~GCFLAG_HAS_FINALIZER
+                    #debug_print("this object has a finalizer")
+                    pending.append(obj)
+                    pending.append(NULL)   # marker
+                #
+                if self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS == 0:
+                    self.header(obj).tid |= GCFLAG_TRACK_YOUNG_PTRS
+                    self.trace_and_drag_out_of_nursery(obj)
+                #
             else:
-                # Remember the finalizer in the dict
-                finalizer_funcs.setitem(obj, func)
-                self.objects_to_trace.append(obj)
-        #
-        # Follow all refs
-        self.remember_young_rawmalloced_visited = self.AddressStack()
-        self.collect_oldrefs_to_nursery()
-        #
-        # Reset GCFLAG_VISITED on young rawmalloced objects added just before
-        self.remember_young_rawmalloced_visited.foreach(
-            self._remove_gcflag_visited, None)
-        self.remember_young_rawmalloced_visited.delete()
-        self.remember_young_rawmalloced_visited = None
-        #
-        # At this point all objects reachable from 'finalizer_funcs'
-        # are disconnected from the rest of the world, and none has
-        # the GCFLAG_VISITED set.  Use the generic method.
-        self._deal_with_objects_with_finalizers(finalizer_funcs)
+                # seen a NULL marker
+                obj = pending.pop()
+                #debug_print("adding to scheduled", obj)
+                self.finalizers_scheduled.append(obj)
 
+    @staticmethod
+    def _move_to_old_finalizer(obj, finalizer, old_objects_with_finalizers):
+        if finalizer != NULL:
+            old_objects_with_finalizers.append(obj)
+            old_objects_with_finalizers.append(finalizer)
 
-    def _remove_gcflag_visited(self, obj, ignored):
-        # 'obj' has GCFLAG_VISITED; remove it.
-        ll_assert(self.header(obj).tid & GCFLAG_VISITED != 0,
-                  "remove_gcflag_visited: not?")
-        self.header(obj).tid &= ~GCFLAG_VISITED
 
-
-    def _deal_with_objects_with_finalizers(self, finalizer_funcs):
+    def deal_with_old_objects_with_finalizers(self):
         # Walk over list of objects with finalizers.
         # If it is not surviving, add it to the list of to-be-called
         # finalizers and make it survive, to make the finalizer runnable.
@@ -2003,7 +2021,28 @@
         # CPython does.  The details of this algorithm are in
         # pypy/doc/discussion/finalizer-order.txt.
         #
-        xxxxxxxxxxx
+        ll_assert(not self.objects_to_trace.non_empty(),
+                  "objects_to_trace non empty [deal_old_finalizer]")
+        #
+        old_objs = self.old_objects_with_finalizers
+        self.old_objects_with_finalizers = self.AddressStack()
+        finalizer_funcs = self.AddressDict()
+        #
+        while old_objs.non_empty():
+            func = old_objs.pop()
+            obj = old_objs.pop()
+            ll_assert(bool(self.header(obj).tid & GCFLAG_HAS_FINALIZER),
+                      "lost GCFLAG_HAS_FINALIZER")
+            #
+            if self.header(obj).tid & GCFLAG_VISITED:
+                # surviving
+                self.old_objects_with_finalizers.append(obj)
+                self.old_objects_with_finalizers.append(func)
+                #
+            else:
+                # dying
+                self.objects_to_trace.append(obj)
+                finalizer_funcs.setitem(obj, func)
         #
         # Now follow all the refs
         finalizers_scheduled = self.AddressStack()
@@ -2037,33 +2076,6 @@
         old_objs.delete()
 
 
-    def deal_with_old_objects_with_finalizers(self):
-        ll_assert(not self.objects_to_trace.non_empty(),
-                  "objects_to_trace non empty [deal_old_finalizer]")
-        #
-        old_objs = self.old_objects_with_finalizers
-        self.old_objects_with_finalizers = self.AddressStack()
-        finalizer_funcs = self.AddressDict()
-        #
-        while old_objs.non_empty():
-            func = old_objs.pop()
-            obj = old_objs.pop()
-            ll_assert(bool(self.header(obj).tid & GCFLAG_HAS_FINALIZER),
-                      "lost GCFLAG_HAS_FINALIZER")
-            #
-            if self.header(obj).tid & GCFLAG_VISITED:
-                # surviving
-                self.old_objects_with_finalizers.append(obj)
-                self.old_objects_with_finalizers.append(func)
-                #
-            else:
-                # dying
-                self.objects_to_trace.append(obj)
-                finalizer_funcs.setitem(obj, func)
-        #
-        self._deal_with_objects_with_finalizers(finalizer_funcs)
-
-
     # ----------
     # Weakrefs
 
diff --git a/rpython/memory/test/snippet.py b/rpython/memory/test/snippet.py
--- a/rpython/memory/test/snippet.py
+++ b/rpython/memory/test/snippet.py
@@ -12,7 +12,6 @@
     def definestr_finalizer_order(cls):
         import random
         x = random.randrange(0,10000)
-        x = 2696
         print "R"*1000
         print x
         print '-'*60
@@ -20,7 +19,7 @@
         from rpython.tool.algo import graphlib
 
         cls.finalizer_order_examples = examples = []
-        if 1: # cls.large_tests_ok:
+        if cls.large_tests_ok:
             letters = 'abcdefghijklmnopqrstuvwxyz'
             COUNT = 20
         else:
@@ -77,7 +76,7 @@
                 vertices[c].refs.append(vertices[d])
 
         def f(_):
-            i = 2
+            i = 0
             while i < len(examples):
                 debug_print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<")
                 input, components, strict = examples[i]
diff --git a/rpython/memory/test/test_gc.py b/rpython/memory/test/test_gc.py
--- a/rpython/memory/test/test_gc.py
+++ b/rpython/memory/test/test_gc.py
@@ -1061,7 +1061,7 @@
 
 class TestMiniMarkGCLargeNursery(TestMiniMarkGC):
     GC_PARAMS = {'nursery_size': 16384*WORD}
-    #def setup_class(cls):
-    #    py.test.skip("takes a lot of extra time to run")
-    #def teardown_class(cls):
-    #    pass
+    def setup_class(cls):
+        py.test.skip("takes a lot of extra time to run")
+    def teardown_class(cls):
+        pass
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to