[pypy-svn] r70072 - in pypy/branch/virtual-forcing/pypy: jit/backend/llgraph jit/backend/test jit/backend/x86 jit/metainterp jit/metainterp/test rlib

arigo at codespeak.net arigo at codespeak.net
Fri Dec 11 17:58:42 CET 2009


Author: arigo
Date: Fri Dec 11 17:58:41 2009
New Revision: 70072

Modified:
   pypy/branch/virtual-forcing/pypy/jit/backend/llgraph/llimpl.py
   pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py
   pypy/branch/virtual-forcing/pypy/jit/backend/x86/regalloc.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/executor.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/resoperation.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py
   pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualref.py
   pypy/branch/virtual-forcing/pypy/rlib/jit.py
Log:
Add a new operation 'virtual_ref_check', documented in rlib/jit.
Implement it to replace the hack of the previous checkin.


Modified: pypy/branch/virtual-forcing/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/backend/llgraph/llimpl.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/backend/llgraph/llimpl.py	Fri Dec 11 17:58:41 2009
@@ -154,7 +154,7 @@
     'call_may_force'  : (('int', 'varargs'), 'intorptr'),
     'guard_not_forced': ((), None),
     'virtual_ref'     : (('ref', 'int'), 'ref'),
-    'virtual_ref_finish':(('ref', 'ref'), None),
+    'virtual_ref_check': (('varargs',), None),
     #'getitem'         : (('void', 'ref', 'int'), 'int'),
     #'setitem'         : (('void', 'ref', 'int', 'int'), None),
     #'newlist'         : (('void', 'varargs'), 'ref'),
@@ -818,7 +818,7 @@
     def op_virtual_ref(self, _, virtual, index):
         return virtual
 
-    def op_virtual_ref_finish(self, _, vref, virtual):
+    def op_virtual_ref_check(self, _, *args):
         pass
 
 

Modified: pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py	Fri Dec 11 17:58:41 2009
@@ -786,6 +786,12 @@
                                    'ref')
         assert r.value == u_box.value
 
+    def test_virtual_ref_check(self):
+        # if VIRTUAL_REF_CHECK reaches the backend, it is a no-op
+        self.execute_operation(rop.VIRTUAL_REF_CHECK,
+                               [BoxInt(123), BoxInt(234)],
+                               'void')
+
     def test_jump(self):
         # this test generates small loops where the JUMP passes many
         # arguments of various types, shuffling them around.

Modified: pypy/branch/virtual-forcing/pypy/jit/backend/x86/regalloc.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/backend/x86/regalloc.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/backend/x86/regalloc.py	Fri Dec 11 17:58:41 2009
@@ -928,6 +928,9 @@
     def consider_debug_merge_point(self, op, ignored):
         pass
 
+    def consider_virtual_ref_check(self, op, ignored):
+        self.possibly_free_vars(op.args)
+
     def get_mark_gc_roots(self, gcrootmap):
         shape = gcrootmap.get_basic_shape()
         for v, val in self.sm.stack_bindings.items():

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py	Fri Dec 11 17:58:41 2009
@@ -1158,16 +1158,20 @@
                   self.var_position(op.args[3]))
 
     def serialize_op_jit_marker(self, op):
-        if op.args[0].value == 'jit_merge_point':
-            assert self.portal, "jit_merge_point in non-main graph!"
-            self.emit('jit_merge_point')
-            assert ([self.var_position(i) for i in op.args[2:]] ==
-                    range(0, 2*(len(op.args) - 2), 2))
-            #for i in range(2, len(op.args)):
-            #    arg = op.args[i]
-            #    self._eventualy_builtin(arg)
-        elif op.args[0].value == 'can_enter_jit':
-            self.emit('can_enter_jit')
+        key = op.args[0].value
+        getattr(self, 'handle_jit_marker__%s' % key)(op)
+
+    def handle_jit_marker__jit_merge_point(self, op):
+        assert self.portal, "jit_merge_point in non-main graph!"
+        self.emit('jit_merge_point')
+        assert ([self.var_position(i) for i in op.args[2:]] ==
+                range(0, 2*(len(op.args) - 2), 2))
+
+    def handle_jit_marker__can_enter_jit(self, op):
+        self.emit('can_enter_jit')
+
+    def handle_jit_marker__virtual_ref_check(self, op):
+        self.emit('virtual_ref_check')
 
     def serialize_op_direct_call(self, op):
         kind = self.codewriter.guess_call_kind(op)

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/executor.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/executor.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/executor.py	Fri Dec 11 17:58:41 2009
@@ -226,7 +226,7 @@
 def do_virtual_ref(cpu, box1, box2):
     raise NotImplementedError
 
-def do_virtual_ref_finish(cpu, box1, box2):
+def do_virtual_ref_check(cpu):
     raise NotImplementedError
 
 def do_debug_merge_point(cpu, box1):

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py	Fri Dec 11 17:58:41 2009
@@ -759,26 +759,29 @@
         vrefvalue.setfield(descr_virtual_token, self.getvalue(tokenbox))
         vrefvalue.setfield(descr_virtualref_index, self.getvalue(indexbox))
 
-    def optimize_VIRTUAL_REF_FINISH(self, op):
-        value = self.getvalue(op.args[1])
-        if not value.is_virtual():   # virtual_ref(non-virtual) gives bad
-            raise compile.GiveUp     # results, so don't bother compiling it
-        #
-        # Set the 'forced' field of the virtual_ref.
-        # In good cases, this is all virtual, so has no effect.
-        # Otherwise, this forces the real object -- but only now, as
-        # opposed to much earlier.  This is important because the object is
-        # typically a PyPy PyFrame, and now is the end of its execution, so
-        # forcing it now does not have catastrophic effects.
-        from pypy.jit.metainterp import virtualref
-        # - set 'forced' to point to the real object
-        op1 = ResOperation(rop.SETFIELD_GC, op.args, None,
-                          descr = virtualref.get_descr_forced(self.cpu))
-        self.optimize_SETFIELD_GC(op1)
-        # - set 'virtual_token' to TOKEN_NONE
-        op1 = ResOperation(rop.SETFIELD_GC, [op.args[0], ConstInt(0)], None,
+    def optimize_VIRTUAL_REF_CHECK(self, op):
+        for i in range(0, len(op.args), 2):
+            value = self.getvalue(op.args[i])
+            if not value.is_virtual():   # virtual_ref(non-virtual) means it
+                raise compile.GiveUp     # escaped already, which is bad
+            #
+            # Set the 'forced' field of the virtual_ref.
+            # In good cases, this is all virtual, so has no effect.
+            # Otherwise, this forces the real object -- but only now, as
+            # opposed to much earlier.  This is important because the object is
+            # typically a PyPy PyFrame, and now is the end of its execution, so
+            # forcing it now does not have catastrophic effects.
+            from pypy.jit.metainterp import virtualref
+            # - set 'forced' to point to the real object
+            args = [op.args[i+1], op.args[i]]
+            op1 = ResOperation(rop.SETFIELD_GC, args, None,
+                              descr = virtualref.get_descr_forced(self.cpu))
+            self.optimize_SETFIELD_GC(op1)
+            # - set 'virtual_token' to TOKEN_NONE
+            args = [op.args[i+1], ConstInt(0)]
+            op1 = ResOperation(rop.SETFIELD_GC, args, None,
                           descr = virtualref.get_descr_virtual_token(self.cpu))
-        self.optimize_SETFIELD_GC(op1)
+            self.optimize_SETFIELD_GC(op1)
 
     def optimize_GETFIELD_GC(self, op):
         value = self.getvalue(op.args[0])

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py	Fri Dec 11 17:58:41 2009
@@ -836,6 +836,7 @@
                 except GiveUp:
                     self.metainterp.staticdata.profiler.count(ABORT_BRIDGE)
                     self.metainterp.switch_to_blackhole()
+            self.metainterp.generate_virtual_ref_check()
         if self.metainterp.is_blackholing():
             self.blackhole_reached_merge_point(self.env)
         return True
@@ -888,6 +889,22 @@
 
     @arguments("box")
     def opimpl_virtual_ref(self, box):
+        # Details on the content of metainterp.virtualref_boxes:
+        #
+        #  * it's a list whose items go two by two, containing first the
+        #    virtual box (e.g. the PyFrame) and then the vref box (e.g.
+        #    the 'virtual_ref(frame)').
+        #
+        #  * if we detect that the virtual box escapes during tracing
+        #    already (by generating a CALl_MAY_FORCE that marks the flags
+        #    in the vref), then we replace the vref in the list with
+        #    ConstPtr(NULL).
+        #
+        #  * at the next virtual_ref_check() or jit_merge_point, any such
+        #    NULL causes tracing to abort.  So escaping is fine if there
+        #    is no virtual_ref_check() or jit_merge_point before the final
+        #    call to virtual_ref_finish().
+        #
         metainterp = self.metainterp
         if metainterp.is_blackholing():
             resbox = box      # good enough when blackholing
@@ -913,34 +930,19 @@
         # virtual_ref_finish() assumes that we have a stack-like, last-in
         # first-out order.
         metainterp = self.metainterp
+        if not metainterp.is_blackholing():
+            vrefbox = metainterp.virtualref_boxes[-1]
+            vref = vrefbox.getref_base()
+            if virtualref.is_virtual_ref(vref):
+                metainterp.stop_tracking_virtualref(-2)
+        #
         vrefbox = metainterp.virtualref_boxes.pop()
         lastbox = metainterp.virtualref_boxes.pop()
         assert box.getref_base() == lastbox.getref_base()
-        if not metainterp.is_blackholing():
-            if vrefbox.getref_base():
-                metainterp.history.record(rop.VIRTUAL_REF_FINISH,
-                                          [vrefbox, lastbox], None)
-
-    def cancel_tracking_virtual_ref(self, argboxes):
-        # if the most recent vref points to an object that escapes in a
-        # residual call (i.e. is in argboxes), then cancel its special
-        # treatment and allow it to escape.  XXX check and document more, or
-        # find another approach -- see test_recursive_call in test_virtualref
-        metainterp = self.metainterp
-        if metainterp.is_blackholing():
-            return
-        if len(metainterp.virtualref_boxes) == 0:
-            return
-        lastbox = metainterp.virtualref_boxes[-2]
-        if lastbox not in argboxes:
-            return
-        vrefbox = metainterp.virtualref_boxes[-1]
-        if vrefbox.getref_base():
-            metainterp.history.record(rop.VIRTUAL_REF_FINISH,
-                                      [vrefbox, lastbox], None)
-            ConstRef = metainterp.cpu.ts.ConstRef
-            nullbox = ConstRef(ConstRef.value)
-            metainterp.virtualref_boxes[-1] = nullbox
+
+    @arguments()
+    def opimpl_virtual_ref_check(self):
+        self.metainterp.generate_virtual_ref_check()
 
     # ------------------------------
 
@@ -1045,7 +1047,6 @@
     def do_residual_call(self, argboxes, descr, exc):
         effectinfo = descr.get_extra_info()
         if effectinfo is None or effectinfo.forces_virtual_or_virtualizable:
-            self.cancel_tracking_virtual_ref(argboxes)
             # residual calls require attention to keep virtualizables in-sync
             self.metainterp.vable_and_vrefs_before_residual_call()
             # xxx do something about code duplication
@@ -1790,8 +1791,6 @@
         for i in range(1, len(self.virtualref_boxes), 2):
             vrefbox = self.virtualref_boxes[i]
             vref = vrefbox.getref_base()
-            if not vref:
-                continue
             virtualref.tracing_before_residual_call(vref)
             # the FORCE_TOKEN is already set at runtime in each vref when
             # it is created, by optimizeopt.py.
@@ -1817,11 +1816,9 @@
             for i in range(1, len(self.virtualref_boxes), 2):
                 vrefbox = self.virtualref_boxes[i]
                 vref = vrefbox.getref_base()
-                if not vref:
-                    continue
                 if virtualref.tracing_after_residual_call(vref):
                     # this vref escaped during CALL_MAY_FORCE.
-                    escapes = True
+                    self.stop_tracking_virtualref(i-1)
             #
             vinfo = self.staticdata.virtualizable_info
             if vinfo is not None:
@@ -1837,6 +1834,44 @@
         if escapes:
             self.load_fields_from_virtualizable()
 
+    def generate_virtual_ref_check(self):
+        if self.is_blackholing():
+            return
+        # first, abort tracing if we reach this point with an escaped virtual
+        for i in range(1, len(self.virtualref_boxes), 2):
+            vrefbox = self.virtualref_boxes[i]
+            vref = vrefbox.getref_base()
+            if not virtualref.is_virtual_ref(vref):
+                self.switch_to_blackhole()
+                return
+        # then record VIRTUAL_REF_CHECK, with no argument so far.
+        # Arguments may be added by stop_tracking_virtualref().
+        self.history.record(rop.VIRTUAL_REF_CHECK, [], None)
+
+    def stop_tracking_virtualref(self, j):
+        # we look for the most recent VIRTUAL_REF_CHECK marker, and add
+        # there the pair virtualbox/vrefbox as arguments.
+        virtualbox = self.virtualref_boxes[j]
+        vrefbox = self.virtualref_boxes[j+1]
+        assert virtualref.is_virtual_ref(vrefbox.getref_base())
+        self.virtualref_boxes[j+1] = self.cpu.ts.CONST_NULL
+        operations = self.history.operations
+        for i in range(len(operations)-1, -1, -1):
+            op = operations[i]
+            if op.opnum == rop.VIRTUAL_REF_CHECK:
+                # found
+                op.args = op.args + [virtualbox, vrefbox]
+                break
+            if op.result is vrefbox:
+                # no VIRTUAL_REF_CHECK exists before the VIRTUAL_REF
+                # that created this vref.  Replace it with a mere SAME_AS.
+                if op.opnum == rop.VIRTUAL_REF:
+                    op.opnum = rop.SAME_AS
+                    op.args = [op.args[0]]
+                break
+        else:
+            pass    # not found at all!  nothing to do, just ignore it
+
     def handle_exception(self):
         etype = self.cpu.get_exception()
         evalue = self.cpu.get_exc_value()
@@ -1877,8 +1912,6 @@
         for i in range(0, len(virtualref_boxes), 2):
             virtualbox = virtualref_boxes[i]
             vrefbox = virtualref_boxes[i+1]
-            if not vrefbox.getref_base():
-                continue
             virtualref.continue_tracing(vrefbox.getref_base(),
                                         virtualbox.getref_base())
         #

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/resoperation.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/resoperation.py	Fri Dec 11 17:58:41 2009
@@ -223,7 +223,7 @@
     'COND_CALL_GC_MALLOC',  # [a, b, if_(a<=b)_result, if_(a>b)_call, args...]
                             #        => result          (for mallocs)
     'DEBUG_MERGE_POINT/1',      # debugging only
-    'VIRTUAL_REF_FINISH/2',
+    'VIRTUAL_REF_CHECK',
 
     '_CANRAISE_FIRST', # ----- start of can_raise operations -----
     'CALL',

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py	Fri Dec 11 17:58:41 2009
@@ -1,7 +1,7 @@
 import py
 from pypy.rpython.lltypesystem import lltype, llmemory, lloperation
-from pypy.rlib.jit import JitDriver, dont_look_inside
-from pypy.rlib.jit import virtual_ref, virtual_ref_finish, vref_None
+from pypy.rlib.jit import JitDriver, dont_look_inside, vref_None
+from pypy.rlib.jit import virtual_ref, virtual_ref_check, virtual_ref_finish
 from pypy.rlib.objectmodel import compute_unique_id
 from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
 from pypy.jit.metainterp.resoperation import rop
@@ -22,6 +22,7 @@
         def f():
             x = X()
             exctx.topframeref = virtual_ref(x)
+            virtual_ref_check()
             exctx.topframeref = vref_None
             virtual_ref_finish(x)
             return 1
@@ -29,7 +30,7 @@
         self.interp_operations(f, [])
         self.check_operations_history(new_with_vtable=1,     # X()
                                       virtual_ref=1,
-                                      virtual_ref_finish=1)
+                                      virtual_ref_check=1)
 
     def test_make_vref_guard(self):
         if not isinstance(self, TestLLtype):
@@ -53,6 +54,7 @@
             exctx.topframeref = virtual_ref(x)
         def leave():
             exctx.topframeref = vref_None
+            virtual_ref_check()
             virtual_ref_finish(exctx._frame)
         def f(n):
             enter(n)
@@ -105,6 +107,7 @@
                 # here, 'x' should be virtual. (This is ensured because
                 # we call virtual_ref(x).)
                 exctx.topframeref = vref_None
+                virtual_ref_check()
                 virtual_ref_finish(x)
                 # 'x' is allowed to escape, and even be forced, even after
                 # the call to finish().
@@ -114,8 +117,72 @@
         #
         self.meta_interp(f, [10])
         self.check_loops(new_with_vtable=2)   # the vref, and later the X
+        self.check_aborted_count(0)
+
+    def test_make_vref_and_force_nocheck_1(self):
+        jitdriver = JitDriver(greens = [], reds = ['total', 'n'])
+        #
+        class X:
+            pass
+        class ExCtx:
+            pass
+        exctx = ExCtx()
+        #
+        @dont_look_inside
+        def force_me():
+            return exctx.topframeref().n
+        #
+        def f(n):
+            total = 0
+            while total < 300:
+                jitdriver.can_enter_jit(total=total, n=n)
+                jitdriver.jit_merge_point(total=total, n=n)
+                x = X()
+                x.n = n + 123
+                exctx.topframeref = virtual_ref(x)
+                # --- no virtual_ref_check() here ---
+                total += force_me() - 100
+                virtual_ref_finish(x)
+                exctx.topframeref = vref_None
+            return total
+        #
+        res = self.meta_interp(f, [-4])
+        assert res == 16 * 19
+        self.check_aborted_count(0)
+
+    def test_make_vref_and_force_nocheck_2(self):
+        jitdriver = JitDriver(greens = [], reds = ['total', 'n'])
+        #
+        class X:
+            pass
+        class ExCtx:
+            pass
+        exctx = ExCtx()
+        #
+        @dont_look_inside
+        def force_me():
+            return exctx.topframeref().n
+        #
+        def f(n):
+            total = 0
+            while total < 300:
+                jitdriver.can_enter_jit(total=total, n=n)
+                jitdriver.jit_merge_point(total=total, n=n)
+                x = X()
+                x.n = n + 123
+                exctx.topframeref = virtual_ref(x)
+                virtual_ref_check()
+                total += force_me() - 100
+                # --- but no virtual_ref_check() there ---
+                virtual_ref_finish(x)
+                exctx.topframeref = vref_None
+            return total
+        #
+        res = self.meta_interp(f, [-4])
+        assert res == 16 * 19
+        self.check_aborted_count(0)
 
-    def test_make_vref_and_force(self):
+    def test_make_vref_and_force_check(self):
         jitdriver = JitDriver(greens = [], reds = ['total', 'n'])
         #
         class X:
@@ -137,6 +204,7 @@
                 x.n = n + 123
                 exctx.topframeref = virtual_ref(x)
                 total += force_me() - 100
+                virtual_ref_check()
                 virtual_ref_finish(x)
                 exctx.topframeref = vref_None
             return total
@@ -175,11 +243,13 @@
                 xy.next1 = None
                 xy.next2 = None
                 xy.next3 = None
+                virtual_ref_check()
                 virtual_ref_finish(xy)
         #
         self.meta_interp(f, [15])
         self.check_loops(new_with_vtable=2)     # the vref, and xy so far,
                                                 # but not xy.next1/2/3
+        self.check_aborted_count(0)
 
     def test_simple_force_always(self):
         myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -204,6 +274,7 @@
                 xy.n = n
                 exctx.topframeref = virtual_ref(xy)
                 n -= externalfn(n)
+                virtual_ref_check()
                 virtual_ref_finish(xy)
                 exctx.topframeref = vref_None
         #
@@ -234,6 +305,7 @@
                 xy.n = n
                 exctx.topframeref = virtual_ref(xy)
                 n -= externalfn(n)
+                virtual_ref_check()
                 virtual_ref_finish(xy)
                 exctx.topframeref = vref_None
             return exctx.m
@@ -241,6 +313,7 @@
         res = self.meta_interp(f, [30])
         assert res == 13
         self.check_loop_count(1)
+        self.check_aborted_count(0)
 
     def test_blackhole_forces(self):
         myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -267,12 +340,14 @@
                     externalfn(n)
                 n -= 1
                 exctx.topframeref = vref_None
+                virtual_ref_check()
                 virtual_ref_finish(xy)
             return exctx.m
         #
         res = self.meta_interp(f, [30])
         assert res == 13
         self.check_loop_count(1)
+        self.check_aborted_count(0)
 
     def test_bridge_forces(self):
         myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -299,12 +374,14 @@
                     externalfn(n)
                 n -= 1
                 exctx.topframeref = vref_None
+                virtual_ref_check()
                 virtual_ref_finish(xy)
             return exctx.m
         #
         res = self.meta_interp(f, [72])
         assert res == 6
         self.check_loop_count(1)     # the bridge should not be compiled
+        self.check_aborted_count_at_least(1)
 
     def test_access_vref_later(self):
         myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -320,7 +397,6 @@
             return exctx.later().n
         #
         def f(n):
-            later = None
             while n > 0:
                 myjitdriver.can_enter_jit(n=n)
                 myjitdriver.jit_merge_point(n=n)
@@ -330,11 +406,13 @@
                 exctx.later = exctx.topframeref
                 n -= 1
                 exctx.topframeref = vref_None
+                virtual_ref_check()
                 virtual_ref_finish(xy)
             return g()
         #
         res = self.meta_interp(f, [15])
         assert res == 1
+        self.check_aborted_count(0)
 
     def test_jit_force_virtual_seen(self):
         myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -354,6 +432,7 @@
                 exctx.topframeref = virtual_ref(xy)
                 n = exctx.topframeref().n - 1
                 exctx.topframeref = vref_None
+                virtual_ref_check()
                 virtual_ref_finish(xy)
             return 1
         #

Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualref.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualref.py	(original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualref.py	Fri Dec 11 17:58:41 2009
@@ -76,12 +76,22 @@
     vref.forced = lltype.cast_opaque_ptr(rclass.OBJECTPTR, real_object)
     return lltype.cast_opaque_ptr(llmemory.GCREF, vref)
 
+def is_virtual_ref(gcref):
+    if not gcref:
+        return False
+    inst = lltype.cast_opaque_ptr(rclass.OBJECTPTR, gcref)
+    return inst.typeptr == jit_virtual_ref_vtable
+
 def tracing_before_residual_call(gcref):
+    if not is_virtual_ref(gcref):
+        return
     vref = lltype.cast_opaque_ptr(lltype.Ptr(JIT_VIRTUAL_REF), gcref)
     assert not vref.virtual_token
     vref.virtual_token = TOKEN_TRACING_RESCALL
 
 def tracing_after_residual_call(gcref):
+    if not is_virtual_ref(gcref):
+        return False
     vref = lltype.cast_opaque_ptr(lltype.Ptr(JIT_VIRTUAL_REF), gcref)
     if vref.virtual_token:
         # not modified by the residual call; assert that it is still
@@ -94,6 +104,8 @@
         return True
 
 def forced_single_vref(gcref, real_object):
+    if not is_virtual_ref(gcref):
+        return
     assert real_object
     vref = lltype.cast_opaque_ptr(lltype.Ptr(JIT_VIRTUAL_REF), gcref)
     assert (vref.virtual_token != TOKEN_NONE and
@@ -102,6 +114,8 @@
     vref.forced = lltype.cast_opaque_ptr(rclass.OBJECTPTR, real_object)
 
 def continue_tracing(gcref, real_object):
+    if not is_virtual_ref(gcref):
+        return
     vref = lltype.cast_opaque_ptr(lltype.Ptr(JIT_VIRTUAL_REF), gcref)
     assert vref.virtual_token != TOKEN_TRACING_RESCALL
     vref.virtual_token = TOKEN_NONE

Modified: pypy/branch/virtual-forcing/pypy/rlib/jit.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/rlib/jit.py	(original)
+++ pypy/branch/virtual-forcing/pypy/rlib/jit.py	Fri Dec 11 17:58:41 2009
@@ -112,11 +112,18 @@
     dereferenced (by the call syntax 'vref()') before the
     virtual_ref_finish, then we get out of the assembler.  If it is not
     dereferenced at all, or only after the virtual_ref_finish, then
-    nothing special occurs.
+    nothing special occurs.  Note that the checks for 'being virtual'
+    only occurs when virtual_ref_check() is called (mostly for testing),
+    or when jit_merge_point is called by JITted code in a recursive call.
     """
     return DirectJitVRef(x)
 virtual_ref.oopspec = 'virtual_ref(x)'
 
+def virtual_ref_check():
+    from pypy.rpython.lltypesystem import lltype, lloperation
+    lloperation.llop.jit_marker(lltype.Void,
+                                lloperation.void('virtual_ref_check'))
+
 def virtual_ref_finish(x):
     """See docstring in virtual_ref(x).  Note that virtual_ref_finish
     takes as argument the real object, not the vref."""



More information about the Pypy-commit mailing list