[pypy-svn] r52499 - in pypy/branch/jit-hotpath/pypy: jit/rainbow jit/rainbow/test jit/timeshifter jit/tl rpython rpython/lltypesystem

arigo at codespeak.net arigo at codespeak.net
Fri Mar 14 14:57:31 CET 2008


Author: arigo
Date: Fri Mar 14 14:57:29 2008
New Revision: 52499

Modified:
   pypy/branch/jit-hotpath/pypy/jit/rainbow/fallback.py
   pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_hotpath.py
   pypy/branch/jit-hotpath/pypy/jit/timeshifter/oop.py
   pypy/branch/jit-hotpath/pypy/jit/tl/tlr.py
   pypy/branch/jit-hotpath/pypy/rpython/llinterp.py
   pypy/branch/jit-hotpath/pypy/rpython/lltypesystem/llmemory.py
Log:
test_hp_tlr passes :-)


Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/fallback.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/jit/rainbow/fallback.py	(original)
+++ pypy/branch/jit-hotpath/pypy/jit/rainbow/fallback.py	Fri Mar 14 14:57:29 2008
@@ -71,6 +71,18 @@
         for box in frame.local_boxes:
             self.local_red.append(self.getinitialboxgv(box))
 
+    def capture_exception(self, e):
+        if not we_are_translated():
+            from pypy.rpython.llinterp import LLException
+            if not isinstance(e, LLException):
+                raise      # don't know how to capture it, and it
+                           # probably shows a bug anyway
+            lltype, llvalue = e.args
+            self.gv_exc_type  = self.rgenop.genconst(lltype)
+            self.gv_exc_value = self.rgenop.genconst(llvalue)
+        else:
+            xxx
+
     def run_directly(self, greenargs, redargs, targetbytecode):
         assert not (greenargs and redargs)  # XXX for now
         calldesc = targetbytecode.owncalldesc
@@ -79,9 +91,17 @@
                                            targetbytecode.gv_ownfnptr,
                                            greenargs or redargs)
         except Exception, e:
-            XXX
+            self.capture_exception(e)
+            gv_res = calldesc.gv_whatever_return_value
         return gv_res
 
+    def oopspec_call(self, oopspec, arglist):
+        try:
+            return oopspec.do_call(self.rgenop, arglist)
+        except Exception, e:
+            self.capture_exception(e)
+            return oopspec.gv_whatever_return_value
+
     def leave_fallback_interp(self, gv_result):
         # at this point we might have an exception set in self.gv_exc_xxx
         # and we have to really raise it.
@@ -277,35 +297,35 @@
 
     @arguments("oopspec", "bool", returns="red")
     def opimpl_red_oopspec_call_0(self, oopspec, deepfrozen):
-        return oopspec.do_call(self.rgenop, [])
+        return self.oopspec_call(oopspec, [])
 
     @arguments("oopspec", "bool", "red", returns="red")
     def opimpl_red_oopspec_call_1(self, oopspec, deepfrozen, arg1):
-        return oopspec.do_call(self.rgenop, [arg1])
+        return self.oopspec_call(oopspec, [arg1])
 
     @arguments("oopspec", "bool", "red", "red", returns="red")
     def opimpl_red_oopspec_call_2(self, oopspec, deepfrozen, arg1, arg2):
-        return oopspec.do_call(self.rgenop, [arg1, arg2])
+        return self.oopspec_call(oopspec, [arg1, arg2])
 
     @arguments("oopspec", "bool", "red", "red", "red", returns="red")
     def opimpl_red_oopspec_call_3(self, oopspec, deepfrozen, arg1, arg2, arg3):
-        return oopspec.do_call(self.rgenop, [arg1, arg2, arg3])
+        return self.oopspec_call(oopspec, [arg1, arg2, arg3])
 
     @arguments("oopspec", "bool")
     def opimpl_red_oopspec_call_noresult_0(self, oopspec, deepfrozen):
-        oopspec.do_call(self.rgenop, [])
+        self.oopspec_call(oopspec, [])
 
     @arguments("oopspec", "bool", "red")
     def opimpl_red_oopspec_call_noresult_1(self, oopspec, deepfrozen, arg1):
-        oopspec.do_call(self.rgenop, [arg1])
+        self.oopspec_call(oopspec, [arg1])
 
     @arguments("oopspec", "bool", "red", "red")
     def opimpl_red_oopspec_call_noresult_2(self, oopspec, deepfrozen, arg1, arg2):
-        oopspec.do_call(self.rgenop, [arg1, arg2])
+        self.oopspec_call(oopspec, [arg1, arg2])
 
     @arguments("oopspec", "bool", "red", "red", "red")
     def opimpl_red_oopspec_call_noresult_3(self, oopspec, deepfrozen, arg1, arg2, arg3):
-        oopspec.do_call(self.rgenop, [arg1, arg2, arg3])
+        self.oopspec_call(oopspec, [arg1, arg2, arg3])
 
     @arguments("red", "calldesc", "bool", "bool", "red_varargs",
                "promotiondesc")

Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_hotpath.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_hotpath.py	(original)
+++ pypy/branch/jit-hotpath/pypy/jit/rainbow/test/test_hotpath.py	Fri Mar 14 14:57:29 2008
@@ -15,6 +15,38 @@
     def __init__(self, result):
         self.result = result
 
+def summary_loops(graph):
+    # Find all operations that are inside a loop.
+    # Ignore the 'default' path of exitswitches, because they are
+    # part of the pseudo-loop that jumps back to the exitswitch
+    # after compiling more code.
+    def visit(block):
+        if block not in stackpos:
+            stackpos[block] = len(blockstack)
+            blockstack.append(block)
+            for link in block.exits:
+                if getattr(link, 'exitcase', None) != 'default':
+                    visit(link.target)
+            blockstack.pop()
+            stackpos[block] = None
+        else:
+            if stackpos[block] is not None:   # back-edge
+                for b in blockstack[stackpos[block]:]:
+                    blocks_in_loop[b] = True
+    blockstack = []
+    stackpos = {}
+    blocks_in_loop = {}
+    visit(graph.startblock)
+    # count operations
+    insns = {}
+    for block in blocks_in_loop:
+        for op in block.operations:
+            if op.opname != 'same_as':
+                insns[op.opname] = insns.get(op.opname, 0) + 1
+    return insns
+
+# ____________________________________________________________
+
 class HotPathTest(test_interpreter.InterpretationTest):
     type_system = 'lltype'
 
@@ -68,6 +100,13 @@
             counts['direct_call'] += 1
         self.check_insns(expected, **counts)
 
+    def check_insns_in_loops(self, expected=None, **counts):
+        self.insns_in_loops = summary_loops(self.get_residual_graph())
+        if expected is not None:
+            assert self.insns_in_loops == expected
+        for opname, count in counts.items():
+            assert self.insns_in_loops.get(opname, 0) == count
+
 
 class TestHotPath(HotPathTest):
 
@@ -298,7 +337,6 @@
             ])
 
     def test_hp_tlr(self):
-        py.test.skip("in-progress")
         from pypy.jit.tl import tlr
 
         def main(code, n):
@@ -308,31 +346,44 @@
                 bytecode = chr(tlr.RETURN_A)
             return tlr.hp_interpret(bytecode, n)
 
-        res = self.run(main, [1, 71], threshold=4)
+        res = self.run(main, [1, 71], threshold=3)
         assert res == 5041
         self.check_traces([
             "jit_not_entered * stru...} 10 70 * array [ 70, 71, 71 ]",
             "jit_not_entered * stru...} 10 69 * array [ 69, 71, 142 ]",
-            "jit_not_entered * stru...} 10 68 * array [ 68, 71, 213 ]",
             "jit_compile * stru...} 10",
-            "pause at hotsplit in hp_interpret",
+        # we first see the promotion of len(regs) in on_enter_jit()
+            "pause at promote in TLRJitDriver.on_enter_jit_Hv",
+        # followed by two fallback runs
+            "run_machine_code * stru...} 10 68 * array [ 68, 71, 213 ]",
+            "fallback_interp",
+            "fb_leave * stru...} 10 68 * array [ 68, 71, 213 ]",
             "run_machine_code * stru...} 10 67 * array [ 67, 71, 284 ]",
             "fallback_interp",
-            "fb_leave * stru...} 10 66 * array [ 66, 71, 355 ]",
+            "fb_leave * stru...} 10 67 * array [ 67, 71, 284 ]",
+        # the third time, we resume compiling for len(regs) == 3
             "run_machine_code * stru...} 10 66 * array [ 66, 71, 355 ]",
+            "jit_resume Signed path 3 in TLRJitDriver.on_enter_jit_Hv",
+        # pause at the "int_is_true" from the JUMP_IF_A opcode
+            "pause at hotsplit in hp_interpret",
+        # two fallback runs off this hotsplit
+            "resume_machine_code",
             "fallback_interp",
             "fb_leave * stru...} 10 65 * array [ 65, 71, 426 ]",
             "run_machine_code * stru...} 10 65 * array [ 65, 71, 426 ]",
             "fallback_interp",
             "fb_leave * stru...} 10 64 * array [ 64, 71, 497 ]",
+        # the third time, compile the path "stay in the loop"
             "run_machine_code * stru...} 10 64 * array [ 64, 71, 497 ]",
             "jit_resume Bool path True in hp_interpret",
             "done at jit_merge_point",
+        # the rest is running 100% in machine code
             "resume_machine_code",
+        # fallback interp for the exit path
             "fallback_interp",
             "fb_leave * stru...} 27 0 * array [ 0, 71, 5041 ]",
             ])
-        # We expect only the direct_call from the red split fallback point.
-        # If we get e.g. 7 of them instead it probably means that we see
-        # direct_calls to the ll helpers for the 'regs' list.
-        self.check_insns(direct_call = 1)
+        # check that the residual graph's inner loop has no direct_call (as
+        # would be the case if the 'regs' list was not properly virtualized)
+        self.check_insns_in_loops({'int_add': 2,
+                                   'int_is_true': 1})

Modified: pypy/branch/jit-hotpath/pypy/jit/timeshifter/oop.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/jit/timeshifter/oop.py	(original)
+++ pypy/branch/jit-hotpath/pypy/jit/timeshifter/oop.py	Fri Mar 14 14:57:29 2008
@@ -62,10 +62,12 @@
         self.result_kind = result_kind
         if FUNCTYPE.RESULT is lltype.Void:
             self.errorbox = None
+            self.gv_whatever_return_value = None
         else:
             error_value = exceptiontransform.error_value(FUNCTYPE.RESULT)
             self.errorbox = rvalue.redbox_from_prebuilt_value(RGenOp,
                                                               error_value)
+            self.gv_whatever_return_value = self.errorbox.genvar
         redboxbuilder = rvalue.ll_redboxbuilder(FUNCTYPE.RESULT)
         self.redboxbuilder = redboxbuilder
         self.sigtoken = RGenOp.sigToken(FUNCTYPE)

Modified: pypy/branch/jit-hotpath/pypy/jit/tl/tlr.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/jit/tl/tlr.py	(original)
+++ pypy/branch/jit-hotpath/pypy/jit/tl/tlr.py	Fri Mar 14 14:57:29 2008
@@ -56,9 +56,12 @@
     def on_enter_jit(self):
         # make a copy of the 'regs' list to make it a VirtualList for the JIT
         length = hint(len(self.regs), promote=True)
-        newregs = []
-        for x in self.regs:
-            newregs.append(x)
+        newregs = [0] * length
+        i = 0
+        while i < length:
+            i = hint(i, concrete=True)
+            newregs[i] = self.regs[i]
+            i += 1
         self.regs = newregs
 
 def hp_interpret(bytecode, a):

Modified: pypy/branch/jit-hotpath/pypy/rpython/llinterp.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/rpython/llinterp.py	(original)
+++ pypy/branch/jit-hotpath/pypy/rpython/llinterp.py	Fri Mar 14 14:57:29 2008
@@ -727,7 +727,7 @@
         self.heap.free(obj, flavor=flavor)
 
     def op_zero_gc_pointers_inside(self, obj):
-        raise NotImplementedError("zero_gc_pointers_inside")
+        llmemory.zero_gc_pointers_inside(obj)
 
     def op_getfield(self, obj, field):
         checkptr(obj)

Modified: pypy/branch/jit-hotpath/pypy/rpython/lltypesystem/llmemory.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/rpython/lltypesystem/llmemory.py	(original)
+++ pypy/branch/jit-hotpath/pypy/rpython/lltypesystem/llmemory.py	Fri Mar 14 14:57:29 2008
@@ -687,3 +687,24 @@
                 setattr(dest._obj, name, llvalue)
     else:
         raise TypeError(T)
+
+
+def zero_gc_pointers_inside(obj):
+    T = lltype.typeOf(obj).TO
+    if isinstance(T, lltype.Struct):
+        for name in T._names:
+            FIELDTYPE = getattr(T, name)
+            if isinstance(FIELDTYPE, lltype.Ptr):
+                if FIELDTYPE.TO._gckind == 'gc':
+                    setattr(obj, name, lltype.nullptr(FIELDTYPE.TO))
+            elif isinstance(FIELDTYPE, lltype.ContainerType):
+                zero_gc_pointers_inside(getattr(obj, name))
+    elif isinstance(T, lltype.Array):
+        ITEMTYPE = T.OF
+        if isinstance(ITEMTYPE, lltype.Ptr):
+            if ITEMTYPE.TO._gckind == 'gc':
+                for i in range(len(obj)):
+                    obj[i] = lltype.nullptr(ITEMTYPE.TO)
+        elif isinstance(ITEMTYPE, lltype.ContainerType):
+            for i in range(len(obj)):
+                zero_gc_pointers_inside(obj[i])



More information about the Pypy-commit mailing list