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

arigo at codespeak.net arigo at codespeak.net
Sat Dec 12 13:59:55 CET 2009


Author: arigo
Date: Sat Dec 12 13:59:55 2009
New Revision: 70078

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/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
Log:
Do it another way.  Much simpler and does not suffer from the
issue that virtualref_boxes is out-of-sync if we mangle past
VIRTUAL_REF_CHECK instructions in the trace.


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	Sat Dec 12 13:59:55 2009
@@ -154,7 +154,7 @@
     'call_may_force'  : (('int', 'varargs'), 'intorptr'),
     'guard_not_forced': ((), None),
     'virtual_ref'     : (('ref', 'int'), 'ref'),
-    'virtual_ref_check': (('varargs',), None),
+    'virtual_ref_finish': (('ref', 'ref'), 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_check(self, _, *args):
+    def op_virtual_ref_finish(self, _, vref, virtual):
         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	Sat Dec 12 13:59:55 2009
@@ -786,9 +786,9 @@
                                    '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,
+    def test_virtual_ref_finish(self):
+        # if VIRTUAL_REF_FINISH reaches the backend, it is a no-op
+        self.execute_operation(rop.VIRTUAL_REF_FINISH,
                                [BoxInt(123), BoxInt(234)],
                                'void')
 

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	Sat Dec 12 13:59:55 2009
@@ -928,7 +928,7 @@
     def consider_debug_merge_point(self, op, ignored):
         pass
 
-    def consider_virtual_ref_check(self, op, ignored):
+    def consider_virtual_ref_finish(self, op, ignored):
         self.possibly_free_vars(op.args)
 
     def get_mark_gc_roots(self, gcrootmap):

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	Sat Dec 12 13:59:55 2009
@@ -226,7 +226,7 @@
 def do_virtual_ref(cpu, box1, box2):
     raise NotImplementedError
 
-def do_virtual_ref_check(cpu, *boxes):
+def do_virtual_ref_finish(cpu, box1, box2):
     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	Sat Dec 12 13:59:55 2009
@@ -759,29 +759,27 @@
         vrefvalue.setfield(descr_virtual_token, self.getvalue(tokenbox))
         vrefvalue.setfield(descr_virtualref_index, self.getvalue(indexbox))
 
-    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)
+    def optimize_VIRTUAL_REF_FINISH(self, op):
+        value = self.getvalue(op.args[1])
+        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
+        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
+        args = [op.args[0], ConstInt(0)]
+        op1 = ResOperation(rop.SETFIELD_GC, args, None,
+                      descr = virtualref.get_descr_virtual_token(self.cpu))
+        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	Sat Dec 12 13:59:55 2009
@@ -836,7 +836,7 @@
                 except GiveUp:
                     self.metainterp.staticdata.profiler.count(ABORT_BRIDGE)
                     self.metainterp.switch_to_blackhole()
-            self.metainterp.generate_virtual_ref_check()
+            self.metainterp.virtual_ref_check()
         if self.metainterp.is_blackholing():
             self.blackhole_reached_merge_point(self.env)
         return True
@@ -900,9 +900,9 @@
         #    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
+        #  * 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
+        #    is no virtual_ref_check()/jit_merge_point() before the final
         #    call to virtual_ref_finish().
         #
         metainterp = self.metainterp
@@ -930,19 +930,18 @@
         # 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():
+            vref = vrefbox.getref_base()
+            if virtualref.is_virtual_ref(vref):
+                metainterp.history.record(rop.VIRTUAL_REF_FINISH,
+                                          [vrefbox, lastbox], None)
 
     @arguments()
     def opimpl_virtual_ref_check(self):
-        self.metainterp.generate_virtual_ref_check()
+        self.metainterp.virtual_ref_check()
 
     # ------------------------------
 
@@ -1052,7 +1051,7 @@
             # xxx do something about code duplication
             resbox = self.metainterp.execute_and_record_varargs(
                 rop.CALL_MAY_FORCE, argboxes, descr=descr)
-            self.metainterp.vable_and_vrefs_after_residual_call()
+            self.metainterp.vable_and_vrefs_after_residual_call(argboxes)
             if resbox is not None:
                 self.make_result_box(resbox)
             self.generate_guard(self.pc, rop.GUARD_NOT_FORCED, None, [])
@@ -1807,20 +1806,23 @@
                                                   force_token_box],
                                 None, descr=vinfo.vable_token_descr)
 
-    def vable_and_vrefs_after_residual_call(self):
+    def vable_and_vrefs_after_residual_call(self, argboxes):
         if self.is_blackholing():
             escapes = True
         else:
             escapes = False
             #
-            for i in range(1, len(self.virtualref_boxes), 2):
-                if self.is_blackholing():
-                    break
-                vrefbox = self.virtualref_boxes[i]
+            for i in range(0, len(self.virtualref_boxes), 2):
+                virtualbox = self.virtualref_boxes[i]
+                vrefbox = self.virtualref_boxes[i+1]
                 vref = vrefbox.getref_base()
-                if virtualref.tracing_after_residual_call(vref):
-                    # this vref escaped during CALL_MAY_FORCE.
-                    self.stop_tracking_virtualref(i-1)
+                if (virtualref.tracing_after_residual_call(vref) or
+                    virtualbox in argboxes):    # <-- XXX hack
+                    # this vref was really a virtual_ref, but it escaped
+                    # during this CALL_MAY_FORCE.  Mark this fact by
+                    # generating a VIRTUAL_REF_FINISH on it and replacing
+                    # it by ConstPtr(NULL).
+                    self.stop_tracking_virtualref(i)
             #
             vinfo = self.staticdata.virtualizable_info
             if vinfo is not None:
@@ -1836,43 +1838,28 @@
         if escapes:
             self.load_fields_from_virtualizable()
 
-    def generate_virtual_ref_check(self):
+    def stop_tracking_virtualref(self, i):
+        virtualbox = self.virtualref_boxes[i]
+        vrefbox = self.virtualref_boxes[i+1]
+        # record VIRTUAL_REF_FINISH just before the current CALL_MAY_FORCE
+        call_may_force_op = self.history.operations.pop()
+        assert call_may_force_op.opnum == rop.CALL_MAY_FORCE
+        self.history.record(rop.VIRTUAL_REF_FINISH,
+                            [vrefbox, virtualbox], None)
+        self.history.operations.append(call_may_force_op)
+        # mark by replacing it with ConstPtr(NULL)
+        self.virtualref_boxes[i+1] = self.cpu.ts.CONST_NULL
+
+    def virtual_ref_check(self):
         if self.is_blackholing():
             return
-        # first, abort tracing if we reach this point with an escaped virtual
+        # 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:
-            assert 0, "not found the VIRTUAL_REF nor VIRTUAL_REF_CHECK at all!"
 
     def handle_exception(self):
         etype = self.cpu.get_exception()
@@ -1910,8 +1897,6 @@
             self, newboxes, resumedescr, expect_virtualizable)
         #
         # virtual refs: make the vrefs point to the freshly allocated virtuals
-        if not self.is_blackholing():
-            self.history.record(rop.VIRTUAL_REF_CHECK, [], None)
         self.virtualref_boxes = virtualref_boxes
         for i in range(0, len(virtualref_boxes), 2):
             virtualbox = virtualref_boxes[i]

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	Sat Dec 12 13:59:55 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_CHECK',
+    'VIRTUAL_REF_FINISH/2',
 
     '_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	Sat Dec 12 13:59:55 2009
@@ -30,7 +30,7 @@
         self.interp_operations(f, [])
         self.check_operations_history(new_with_vtable=1,     # X()
                                       virtual_ref=1,
-                                      virtual_ref_check=1)
+                                      virtual_ref_finish=1)
 
     def test_make_vref_guard(self):
         if not isinstance(self, TestLLtype):



More information about the Pypy-commit mailing list