Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r92380:90a0d3659179
Date: 2017-09-14 00:32 +0200
http://bitbucket.org/pypy/pypy/changeset/90a0d3659179/

Log:    Found out that gc.get_objects() returns some, but not all, objects
        with finalizers, in some strange way. More precisely, it completely
        misses objects with finalizers that have recently become
        unreachable, but it no longer misses these objects after the next
        major collection occurred.

diff --git a/rpython/memory/gc/base.py b/rpython/memory/gc/base.py
--- a/rpython/memory/gc/base.py
+++ b/rpython/memory/gc/base.py
@@ -336,6 +336,7 @@
         callback2, attrname = _convert_callback_formats(callback)    # :-/
         setattr(self, attrname, arg)
         self.root_walker.walk_roots(callback2, callback2, callback2)
+        self.enum_live_with_finalizers(callback, arg)
         self.enum_pending_finalizers(callback, arg)
     enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)'
 
@@ -348,6 +349,12 @@
             i += 1
     enum_pending_finalizers._annspecialcase_ = 'specialize:arg(1)'
 
+    def enum_live_with_finalizers(self, callback, arg):
+        # as far as possible, enumerates the live objects with finalizers,
+        # even if they have not been detected as unreachable yet (but may be)
+        pass
+    enum_live_with_finalizers._annspecialcase_ = 'specialize:arg(1)'
+
     def _copy_pending_finalizers_deque(self, deque, copy_fn):
         tmp = self.AddressDeque()
         while deque.non_empty():
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
@@ -2515,6 +2515,11 @@
         MovingGCBase.enumerate_all_roots(self, callback, arg)
     enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)'
 
+    def enum_live_with_finalizers(self, callback, arg):
+        self.probably_young_objects_with_finalizers.foreach(callback, arg, 2)
+        self.old_objects_with_finalizers.foreach(callback, arg, 2)
+    enum_live_with_finalizers._annspecialcase_ = 'specialize:arg(1)'
+
     def _collect_obj(self, obj, ignored):
         # Ignore pinned objects, which are the ones still in the nursery here.
         # Cache effects: don't read any flag out of 'obj' at this point.
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
@@ -1780,6 +1780,11 @@
         MovingGCBase.enumerate_all_roots(self, callback, arg)
     enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)'
 
+    def enum_live_with_finalizers(self, callback, arg):
+        self.probably_young_objects_with_finalizers.foreach(callback, arg, 2)
+        self.old_objects_with_finalizers.foreach(callback, arg, 2)
+    enum_live_with_finalizers._annspecialcase_ = 'specialize:arg(1)'
+
     @staticmethod
     def _collect_obj(obj, objects_to_trace):
         objects_to_trace.append(obj)
diff --git a/rpython/memory/support.py b/rpython/memory/support.py
--- a/rpython/memory/support.py
+++ b/rpython/memory/support.py
@@ -269,22 +269,23 @@
             self.index_in_oldest = index + 1
             return result
 
-        def foreach(self, callback, arg):
+        def foreach(self, callback, arg, step=1):
             """Invoke 'callback(address, arg)' for all addresses in the deque.
             Typically, 'callback' is a bound method and 'arg' can be None.
+            If step > 1, only calls it for addresses multiple of 'step'.
             """
             chunk = self.oldest_chunk
             index = self.index_in_oldest
             while chunk is not self.newest_chunk:
                 while index < chunk_size:
                     callback(chunk.items[index], arg)
-                    index += 1
+                    index += step
                 chunk = chunk.next
-                index = 0
+                index -= chunk_size
             limit = self.index_in_newest
             while index < limit:
                 callback(chunk.items[index], arg)
-                index += 1
+                index += step
         foreach._annspecialcase_ = 'specialize:arg(1)'
 
         def delete(self):
diff --git a/rpython/memory/test/test_support.py 
b/rpython/memory/test/test_support.py
--- a/rpython/memory/test/test_support.py
+++ b/rpython/memory/test/test_support.py
@@ -160,6 +160,10 @@
 
             ll.foreach(callback, 42)
             assert seen == addrs
+            seen = []
+            ll.foreach(callback, 42, step=2)
+            assert seen == addrs[::2]
+
             for a in addrs:
                 b = ll.popleft()
                 assert a == b
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to