[pypy-commit] pypy gc-del-3: Pass all of test_incminimark_gc

arigo pypy.commits at gmail.com
Tue May 3 15:31:18 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: gc-del-3
Changeset: r84176:a12a83151bb7
Date: 2016-05-03 21:31 +0200
http://bitbucket.org/pypy/pypy/changeset/a12a83151bb7/

Log:	Pass all of test_incminimark_gc

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
@@ -2587,20 +2587,23 @@
     # ----------
     # Finalizers
 
+    def call_destructor(self, obj):
+        destructor = self.destructor_or_custom_trace(self.get_type_id(obj))
+        ll_assert(bool(destructor), "no destructor found")
+        destructor(obj)
+
     def deal_with_young_objects_with_destructors(self):
         """We can reasonably assume that destructors don't do
         anything fancy and *just* call them. Among other things
         they won't resurrect objects
         """
-        while self.young_objects_with_light_finalizers.non_empty():
-            obj = self.young_objects_with_light_finalizers.pop()
+        while self.young_objects_with_destructors.non_empty():
+            obj = self.young_objects_with_destructors.pop()
             if not self.is_forwarded(obj):
-                finalizer = self.getlightfinalizer(self.get_type_id(obj))
-                ll_assert(bool(finalizer), "no light finalizer found")
-                finalizer(obj)
+                self.call_destructor(obj)
             else:
                 obj = self.get_forwarding_address(obj)
-                self.old_objects_with_light_finalizers.append(obj)
+                self.old_objects_with_destructors.append(obj)
 
     def deal_with_old_objects_with_destructors(self):
         """We can reasonably assume that destructors don't do
@@ -2608,18 +2611,16 @@
         they won't resurrect objects
         """
         new_objects = self.AddressStack()
-        while self.old_objects_with_light_finalizers.non_empty():
-            obj = self.old_objects_with_light_finalizers.pop()
+        while self.old_objects_with_destructors.non_empty():
+            obj = self.old_objects_with_destructors.pop()
             if self.header(obj).tid & GCFLAG_VISITED:
                 # surviving
                 new_objects.append(obj)
             else:
                 # dying
-                finalizer = self.getlightfinalizer(self.get_type_id(obj))
-                ll_assert(bool(finalizer), "no light finalizer found")
-                finalizer(obj)
-        self.old_objects_with_light_finalizers.delete()
-        self.old_objects_with_light_finalizers = new_objects
+                self.call_destructor(obj)
+        self.old_objects_with_destructors.delete()
+        self.old_objects_with_destructors = new_objects
 
     def deal_with_young_objects_with_finalizers(self):
         while self.probably_young_objects_with_finalizers.non_empty():
diff --git a/rpython/memory/test/gc_test_base.py b/rpython/memory/test/gc_test_base.py
--- a/rpython/memory/test/gc_test_base.py
+++ b/rpython/memory/test/gc_test_base.py
@@ -282,7 +282,7 @@
             llop.gc__collect(lltype.Void)
             aid = b.a.id
             b.a = None
-            # check that __del__ is not called again
+            # check that finalizer_trigger() is not called again
             llop.gc__collect(lltype.Void)
             llop.gc__collect(lltype.Void)
             return b.num_deleted * 10 + aid + 100 * (b.a is None)
@@ -409,23 +409,32 @@
         res = self.interpret(f, [])
         assert res
 
-    def test_cycle_with_weakref_and_del(self):
+    def test_cycle_with_weakref_and_finalizer(self):
         import weakref
         class A(object):
             count = 0
         a = A()
         class B(object):
-            def __del__(self):
-                # when __del__ is called, the weakref to c should be dead
-                if self.ref() is None:
-                    a.count += 10  # ok
-                else:
-                    a.count = 666  # not ok
+            pass
+        class FQ(rgc.FinalizerQueue):
+            Class = B
+            def finalizer_trigger(self):
+                while True:
+                    b = self.next_dead()
+                    if b is None:
+                        break
+                    # when we are here, the weakref to c should be dead
+                    if b.ref() is None:
+                        a.count += 10  # ok
+                    else:
+                        a.count = 666  # not ok
+        fq = FQ()
         class C(object):
             pass
         def g():
             c = C()
             c.b = B()
+            fq.register_finalizer(c.b)
             ref = weakref.ref(c)
             c.b.ref = ref
             return ref
@@ -445,23 +454,32 @@
         a = A()
         expected_invalid = self.WREF_IS_INVALID_BEFORE_DEL_IS_CALLED
         class B(object):
-            def __del__(self):
-                # when __del__ is called, the weakref to myself is still valid
+            pass
+        class FQ(rgc.FinalizerQueue):
+            Class = B
+            def finalizer_trigger(self):
+                # when we are here, the weakref to myself is still valid
                 # in RPython with most GCs.  However, this can lead to strange
                 # bugs with incminimark.  https://bugs.pypy.org/issue1687
                 # So with incminimark, we expect the opposite.
-                if expected_invalid:
-                    if self.ref() is None:
-                        a.count += 10  # ok
+                while True:
+                    b = self.next_dead()
+                    if b is None:
+                        break
+                    if expected_invalid:
+                        if b.ref() is None:
+                            a.count += 10  # ok
+                        else:
+                            a.count = 666  # not ok
                     else:
-                        a.count = 666  # not ok
-                else:
-                    if self.ref() is self:
-                        a.count += 10  # ok
-                    else:
-                        a.count = 666  # not ok
+                        if b.ref() is self:
+                            a.count += 10  # ok
+                        else:
+                            a.count = 666  # not ok
+        fq = FQ()
         def g():
             b = B()
+            fq.register_finalizer(b)
             ref = weakref.ref(b)
             b.ref = ref
             return ref
@@ -479,10 +497,19 @@
         class A(object):
             pass
         class B(object):
-            def __del__(self):
-                self.wref().x += 1
+            pass
+        class FQ(rgc.FinalizerQueue):
+            Class = B
+            def finalizer_trigger(self):
+                while True:
+                    b = self.next_dead()
+                    if b is None:
+                        break
+                    b.wref().x += 1
+        fq = FQ()
         def g(a):
             b = B()
+            fq.register_finalizer(b)
             b.wref = weakref.ref(a)
             # the only way to reach this weakref is via B, which is an
             # object with finalizer (but the weakref itself points to
@@ -567,15 +594,24 @@
             def __init__(self):
                 self.id = b.nextid
                 b.nextid += 1
-            def __del__(self):
-                llop.gc__collect(lltype.Void)
-                b.num_deleted += 1
-                C()
-                C()
+                fq.register_finalizer(self)
         class C(A):
-            def __del__(self):
-                b.num_deleted += 1
-                b.num_deleted_c += 1
+            pass
+        class FQ(rgc.FinalizerQueue):
+            Class = A
+            def finalizer_trigger(self):
+                while True:
+                    a = self.next_dead()
+                    if a is None:
+                        break
+                    llop.gc__collect(lltype.Void)
+                    b.num_deleted += 1
+                    if isinstance(a, C):
+                        b.num_deleted_c += 1
+                    else:
+                        C()
+                        C()
+        fq = FQ()
         def f(x, y):
             persistent_a1 = A()
             persistent_a2 = A()
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
@@ -53,7 +53,7 @@
         def set_age_of(c, newvalue):
             # NB. this used to be a dictionary, but setting into a dict
             # consumes memory.  This has the effect that this test's
-            # __del__ methods can consume more memory and potentially
+            # finalizer_trigger method can consume more memory and potentially
             # cause another collection.  This would result in objects
             # being unexpectedly destroyed at the same 'state.time'.
             state.age[ord(c) - ord('a')] = newvalue
@@ -160,11 +160,22 @@
         class B:
             count = 0
         class A:
-            def __del__(self):
-                self.b.count += 1
+            pass
+
+        class FQ(rgc.FinalizerQueue):
+            Class = A
+            def finalizer_trigger(self):
+                while True:
+                    a = self.next_dead()
+                    if a is None:
+                        break
+                    a.b.count += 1
+        fq = FQ()
+
         def g():
             b = B()
             a = A()
+            fq.register_finalizer(a)
             a.b = b
             i = 0
             lst = [None]


More information about the pypy-commit mailing list