1. Pypy
  2. Untitled project
  3. pypy

Commits

Armin Rigo  committed bc7623f

Minimal support for register_finalizer() in the JIT

  • Participants
  • Parent commits 1a9bed8
  • Branches gc-del

Comments (0)

Files changed (8)

File rpython/jit/backend/llsupport/gc.py

View file
         if self.layoutbuilder is not None:
             type_id = self.layoutbuilder.get_type_id(S)
             assert not self.layoutbuilder.is_weakref_type(S)
-            assert not self.layoutbuilder.has_finalizer(S)
+            assert not self.layoutbuilder.has_destructor(S)
             descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0)
 
     def init_array_descr(self, A, descr):

File rpython/jit/codewriter/jtransform.py

View file
     rewrite_op_ullong_mod_zer      = _do_builtin_call
     rewrite_op_gc_identityhash = _do_builtin_call
     rewrite_op_gc_id           = _do_builtin_call
+    rewrite_op_gc_register_finalizer = _do_builtin_call
     rewrite_op_uint_mod        = _do_builtin_call
     rewrite_op_cast_float_to_uint = _do_builtin_call
     rewrite_op_cast_uint_to_float = _do_builtin_call

File rpython/jit/codewriter/support.py

View file
 def _ll_1_gc_identityhash(x):
     return lltype.identityhash(x)
 
-
 # the following function should not be "@elidable": I can think of
 # a corner case in which id(const) is constant-folded, and then 'const'
 # disappears and is collected too early (possibly causing another object
 def _ll_1_gc_id(ptr):
     return llop.gc_id(lltype.Signed, ptr)
 
+def _ll_2_gc_register_finalizer(obj, func):
+    return llop.gc_register_finalizer(lltype.Void, obj, func)
+
 
 @oopspec("jit.force_virtual(inst)")
 def _ll_1_jit_force_virtual(inst):
 def get_gcid_oopspec(op):
     return 'gc_id', op.args
 
+def get_gcregisterfinalizer_oopspec(op):
+    return 'gc_register_finalizer', op.args
+
 
 RENAMED_ADT_NAME = {
     'list': {
         return get_identityhash_oopspec(op)
     elif op.opname == 'gc_id':
         return get_gcid_oopspec(op)
+    elif op.opname == 'gc_register_finalizer':
+        return get_gcregisterfinalizer_oopspec(op)
     else:
         raise ValueError(op.opname)
 

File rpython/jit/codewriter/test/test_flatten.py

View file
 from rpython.rlib.rarithmetic import ovfcheck, r_uint, r_longlong, r_ulonglong
 from rpython.rlib.jit import dont_look_inside, _we_are_jitted, JitDriver
 from rpython.rlib.objectmodel import keepalive_until_here
-from rpython.rlib import jit
+from rpython.rlib import jit, rgc
 
 
 class FakeRegAlloc:
             float_return %(result_var)s
         """ % {"result_var": result_var, "tmp_var": tmp_var}, transform=True)
 
+    def test_register_finalizer(self):
+        class A(object):
+            def finalizer(self):
+                pass
+        glob_a = A()
+        def f():
+            rgc.register_finalizer(glob_a.finalizer)
+        self.encoding_test(f, [], """
+            residual_call_ir_v $<* fn gc_register_finalizer>, I[$<* fn A.finalizer>], R[$<* struct object>], <Descr>
+            -live-
+            void_return
+        """, transform=True)
+
 
 def check_force_cast(FROM, TO, operations, value):
     """Check that the test is correctly written..."""

File rpython/jit/metainterp/test/test_del.py

View file
         res = self.meta_interp(main, [20])
         assert res == 1001
 
+
 class TestLLtype(DelTests, LLJitMixin):
-    pass
+
+    def test_finalizer(self):
+        mydriver = JitDriver(reds = ['n'], greens = [])
+        class Glob(object):
+            seen = 0
+        glob = Glob()
+        class A(object):
+            def __init__(self):
+                rgc.register_finalizer(self.finalizer)
+            def finalizer(self):
+                glob.seen += 1
+        @dont_look_inside
+        def do_collect():
+            rgc.collect(); rgc.collect()
+        def main(n):
+            glob.seen = 0
+            while n > 0:
+                mydriver.jit_merge_point(n=n)
+                A(); A(); A()
+                n -= 1
+            do_collect()
+            return glob.seen
+        assert main(10) == 30
+        res = self.meta_interp(main, [20])
+        assert res >= 54
+
 
 class TestOOtype(DelTests, OOJitMixin):
     def setup_class(cls):

File rpython/memory/gctransform/framework.py

View file
         v_obj, v_func = hop.spaceop.args
         v_obj_addr = hop.genop("cast_ptr_to_adr", [v_obj],
                                resulttype = llmemory.Address)
+        v_func_addr = hop.genop("cast_ptr_to_adr", [v_func],
+                                resulttype = llmemory.Address)
         hop.genop("direct_call", [self.register_finalizer_ptr,
                                   self.c_const_gc,
-                                  v_obj_addr, v_func],
+                                  v_obj_addr, v_func_addr],
                   resultvar = hop.spaceop.result)
 
 

File rpython/rlib/rgc.py

View file
         r_func, is_method = hop.args_r[0].get_r_implfunc()
         assert is_method
         c_llfn = r_func.get_unique_llfn()
-        v_llfn = hop.genop('cast_ptr_to_adr', [c_llfn],
-                           resulttype=llmemory.Address)
         v_self = hop.genop('cast_pointer', [v_self],
                            resulttype=base_ptr_lltype())
         hop.exception_cannot_occur()
-        return hop.genop('gc_register_finalizer', [v_self, v_llfn],
+        return hop.genop('gc_register_finalizer', [v_self, c_llfn],
                          resulttype=lltype.Void)
 
 class ProgressThroughFinalizerQueueEntry(ExtRegistryEntry):

File rpython/rtyper/llinterp.py

View file
                     self.llinterpreter.finalizer_queue.append((llobj, llfn))
 
     def op_gc_register_finalizer(self, llptr, llfn):
+        llfn = llmemory.cast_ptr_to_adr(llfn)
         if self.heap is llheap:
             llobj = llptr._obj
             for llobj1, llfn1 in self.llinterpreter.finalizer_queue: