[pypy-commit] pypy default: Extend FinalizerQueue to be able to handle low-level GCREF pointers

arigo pypy.commits at gmail.com
Tue Mar 20 02:38:38 EDT 2018


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r94019:c4654fc5b220
Date: 2018-03-20 07:37 +0100
http://bitbucket.org/pypy/pypy/changeset/c4654fc5b220/

Log:	Extend FinalizerQueue to be able to handle low-level GCREF pointers
	directly, instead of high-level instances of some class

diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -385,6 +385,7 @@
     #
     #    Class:
     #        the class (or base class) of finalized objects
+    #        --or-- None to handle low-level GCREFs directly
     #
     #    def finalizer_trigger(self):
     #        called to notify that new items have been put in the queue
@@ -397,11 +398,13 @@
     def next_dead(self):
         if we_are_translated():
             from rpython.rtyper.lltypesystem.lloperation import llop
-            from rpython.rtyper.rclass import OBJECTPTR
-            from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
+            from rpython.rtyper.lltypesystem.llmemory import GCREF
+            from rpython.rtyper.annlowlevel import cast_gcref_to_instance
             tag = FinalizerQueue._get_tag(self)
-            ptr = llop.gc_fq_next_dead(OBJECTPTR, tag)
-            return cast_base_ptr_to_instance(self.Class, ptr)
+            ptr = llop.gc_fq_next_dead(GCREF, tag)
+            if self.Class is not None:
+                ptr = cast_gcref_to_instance(self.Class, ptr)
+            return ptr
         try:
             return self._queue.popleft()
         except (AttributeError, IndexError):
@@ -410,14 +413,18 @@
     @specialize.arg(0)
     @jit.dont_look_inside
     def register_finalizer(self, obj):
-        assert isinstance(obj, self.Class)
+        from rpython.rtyper.lltypesystem.llmemory import GCREF
+        if self.Class is None:
+            assert lltype.typeOf(obj) == GCREF
+        else:
+            assert isinstance(obj, self.Class)
         if we_are_translated():
             from rpython.rtyper.lltypesystem.lloperation import llop
-            from rpython.rtyper.rclass import OBJECTPTR
-            from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr
+            from rpython.rtyper.annlowlevel import cast_instance_to_gcref
             tag = FinalizerQueue._get_tag(self)
-            ptr = cast_instance_to_base_ptr(obj)
-            llop.gc_fq_register(lltype.Void, tag, ptr)
+            if self.Class is not None:
+                obj = cast_instance_to_gcref(obj)
+            llop.gc_fq_register(lltype.Void, tag, obj)
             return
         else:
             self._untranslated_register_finalizer(obj)
diff --git a/rpython/rlib/test/test_rgc.py b/rpython/rlib/test/test_rgc.py
--- a/rpython/rlib/test/test_rgc.py
+++ b/rpython/rlib/test/test_rgc.py
@@ -599,3 +599,94 @@
 
         e = py.test.raises(TyperError, gengraph, f, [])
         assert str(e.value).startswith('the RPython-level __del__() method in')
+
+    def test_translated_boehm(self):
+        self._test_translated(use_gc="boehm", llcase=False)
+
+    def test_translated_boehm_ll(self):
+        self._test_translated(use_gc="boehm", llcase=True)
+
+    def test_translated_incminimark(self):
+        self._test_translated(use_gc="incminimark", llcase=False)
+
+    def test_translated_incminimark_ll(self):
+        self._test_translated(use_gc="incminimark", llcase=True)
+
+    def _test_translated(self, use_gc, llcase):
+        import subprocess
+        from rpython.rlib import objectmodel
+        from rpython.translator.interactive import Translation
+        #
+        class Seen:
+            count = 0
+        class MySimpleFQ(rgc.FinalizerQueue):
+            if not llcase:
+                Class = T_Root
+            else:
+                Class = None
+            def finalizer_trigger(self):
+                seen.count += 1
+        seen = Seen()
+        fq = MySimpleFQ()
+        if not llcase:
+            EMPTY = None
+            llbuilder = T_Int
+        else:
+            from rpython.rtyper.annlowlevel import llstr
+            EMPTY = lltype.nullptr(llmemory.GCREF.TO)
+            def llbuilder(n):
+                return lltype.cast_opaque_ptr(llmemory.GCREF, llstr(str(n)))
+
+        def subfunc():
+            w0 = llbuilder(40); fq.register_finalizer(w0)
+            w1 = llbuilder(41); fq.register_finalizer(w1)
+            w2 = llbuilder(42); fq.register_finalizer(w2)
+            w3 = llbuilder(43); fq.register_finalizer(w3)
+            w4 = llbuilder(44); fq.register_finalizer(w4)
+            w5 = llbuilder(45); fq.register_finalizer(w5)
+            w6 = llbuilder(46); fq.register_finalizer(w6)
+            w7 = llbuilder(47); fq.register_finalizer(w7)
+            w8 = llbuilder(48); fq.register_finalizer(w8)
+            w9 = llbuilder(49); fq.register_finalizer(w9)
+            gc.collect()
+            assert seen.count == 0
+            assert fq.next_dead() is EMPTY
+            objectmodel.keepalive_until_here(w0)
+            objectmodel.keepalive_until_here(w1)
+            objectmodel.keepalive_until_here(w2)
+            objectmodel.keepalive_until_here(w3)
+            objectmodel.keepalive_until_here(w4)
+            objectmodel.keepalive_until_here(w5)
+            objectmodel.keepalive_until_here(w6)
+            objectmodel.keepalive_until_here(w7)
+            objectmodel.keepalive_until_here(w8)
+            objectmodel.keepalive_until_here(w9)
+
+        def main(argv):
+            assert fq.next_dead() is EMPTY
+            subfunc()
+            gc.collect(); gc.collect(); gc.collect()
+            assert seen.count > 0
+            n = fq.next_dead()
+            while True:
+                if not llcase:
+                    assert type(n) is T_Int and 40 <= n.x <= 49
+                else:
+                    from rpython.rtyper.lltypesystem.rstr import STR
+                    assert lltype.typeOf(n) is llmemory.GCREF
+                    p = lltype.cast_opaque_ptr(lltype.Ptr(STR), n)
+                    assert len(p.chars) == 2
+                    assert p.chars[0] == "4"
+                    assert "0" <= p.chars[1] <= "9"
+                n = fq.next_dead()
+                if n is EMPTY:
+                    break
+            print "OK!"
+            return 0
+        #
+        t = Translation(main, gc=use_gc)
+        t.disable(['backendopt'])
+        t.set_backend_extra_options(c_debug_defines=True)
+        exename = t.compile()
+        data = subprocess.check_output([str(exename), '.', '.', '.'])
+        assert data.strip().endswith('OK!')


More information about the pypy-commit mailing list