[pypy-svn] r74784 - in pypy/branch/blackhole-improvement/pypy/jit: codewriter metainterp metainterp/test

arigo at codespeak.net arigo at codespeak.net
Wed May 26 18:32:11 CEST 2010


Author: arigo
Date: Wed May 26 18:32:09 2010
New Revision: 74784

Modified:
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/call.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/codewriter.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/jtransform.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/executor.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_recursive.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/warmspot.py
Log:
Some progress towards getting test_recursive to pass again.


Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/call.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/call.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/call.py	Wed May 26 18:32:09 2010
@@ -15,7 +15,8 @@
 
 
 class CallControl(object):
-    virtualref_info = None  # optionally set from outside to a VirtualRefInfo()
+    virtualref_info = None     # optionally set from outside
+    portal_runner_ptr = None   # optionally set from outside
 
     def __init__(self, cpu=None, portal_graph=None):
         self.cpu = cpu
@@ -119,12 +120,12 @@
     def guess_call_kind(self, op, is_candidate=None):
         if op.opname == 'direct_call':
             funcptr = op.args[0].value
+            if funcptr is self.portal_runner_ptr:
+                return 'recursive'
             funcobj = get_funcobj(funcptr)
             if getattr(funcobj, 'graph', None) is None:
                 return 'residual'
             targetgraph = funcobj.graph
-            if targetgraph is self.portal_graph:
-                return 'recursive'
             if (hasattr(targetgraph, 'func') and
                 hasattr(targetgraph.func, 'oopspec')):
                 return 'builtin'
@@ -164,8 +165,9 @@
         because it is not needed there; it is only used by the blackhole
         interp to really do the call corresponding to 'inline_call' ops.
         """
-        fnptr = self.rtyper.getcallable(graph)
+        fnptr = self.rtyper.type_system.getcallable(graph)
         FUNC = get_functype(lltype.typeOf(fnptr))
+        assert lltype.Ptr(lltype.PyObject) not in FUNC.ARGS
         if self.rtyper.type_system.name == 'ootypesystem':
             XXX
         else:

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/codewriter.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/codewriter.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/codewriter.py	Wed May 26 18:32:09 2010
@@ -71,6 +71,9 @@
     def setup_vrefinfo(self, vrefinfo):
         self.callcontrol.virtualref_info = vrefinfo
 
+    def setup_portal_runner_ptr(self, portal_runner_ptr):
+        self.callcontrol.portal_runner_ptr = portal_runner_ptr
+
     def find_all_graphs(self, policy):
         return self.callcontrol.find_all_graphs(policy)
 

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/jtransform.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/jtransform.py	Wed May 26 18:32:09 2010
@@ -283,11 +283,12 @@
             op1 = [op1, SpaceOperation('-live-', [], None)]
         return op1
 
-    def handle_regular_call(self, op):
+    def handle_regular_call(self, op, targetgraph=None):
         """A direct_call turns into the operation 'inline_call_xxx' if it
         is calling a function that we want to JIT.  The initial arg of
         'inline_call_xxx' is the JitCode of the called function."""
-        [targetgraph] = self.callcontrol.graphs_from(op)
+        if targetgraph is None:
+            [targetgraph] = self.callcontrol.graphs_from(op)
         jitcode = self.callcontrol.get_jitcode(targetgraph,
                                                called_from=self.graph)
         op0 = self.rewrite_call(op, 'inline_call', [jitcode])
@@ -313,6 +314,11 @@
             op1 = self.handle_residual_call(op1 or op)
         return op1
 
+    def handle_recursive_call(self, op):
+        ops = self.promote_greens(op.args[1:])
+        targetgraph = self.callcontrol.portal_graph
+        return ops + self.handle_regular_call(op, targetgraph)
+
     handle_residual_indirect_call = handle_residual_call
 
     def handle_regular_indirect_call(self, op):
@@ -682,28 +688,34 @@
             return Constant(value, lltype.Bool)
         return op
 
-    def rewrite_op_jit_marker(self, op):
-        jitdriver = op.args[1].value
-        self.callcontrol.found_jitdriver(jitdriver)
-        key = op.args[0].value
-        return getattr(self, 'handle_jit_marker__%s' % key)(op, jitdriver)
-
-    def handle_jit_marker__jit_merge_point(self, op, jitdriver):
-        assert self.portal, "jit_merge_point in non-main graph!"
+    def promote_greens(self, args):
+        jitdriver = self.callcontrol.jitdriver
+        assert jitdriver is not None, "order dependency issue?"
         ops = []
         num_green_args = len(jitdriver.greens)
-        for v in op.args[2:2+num_green_args]:
+        for v in args[:num_green_args]:
             if isinstance(v, Variable) and v.concretetype is not lltype.Void:
                 kind = getkind(v.concretetype)
                 ops.append(SpaceOperation('-live-', [], None))
                 ops.append(SpaceOperation('%s_guard_value' % kind,
                                           [v], None))
+        return ops
+
+    def rewrite_op_jit_marker(self, op):
+        self.callcontrol.found_jitdriver(op.args[1].value)
+        key = op.args[0].value
+        return 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!"
+        ops = self.promote_greens(op.args[2:])
+        num_green_args = len(self.callcontrol.jitdriver.greens)
         args = (self.make_three_lists(op.args[2:2+num_green_args]) +
                 self.make_three_lists(op.args[2+num_green_args:]))
-        ops.append(SpaceOperation('jit_merge_point', args, None))
-        return ops
+        op1 = SpaceOperation('jit_merge_point', args, None)
+        return ops + [op1]
 
-    def handle_jit_marker__can_enter_jit(self, op, jitdriver):
+    def handle_jit_marker__can_enter_jit(self, op):
         return SpaceOperation('can_enter_jit', [], None)
 
     def rewrite_op_debug_assert(self, op):

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/executor.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/executor.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/executor.py	Wed May 26 18:32:09 2010
@@ -86,6 +86,7 @@
 
 do_call_pure = do_call
 do_call_loopinvariant = do_call
+do_call_may_force = do_call
 
 def do_getarrayitem_gc(cpu, _, arraybox, indexbox, arraydescr):
     array = arraybox.getref_base()

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/pyjitpl.py	Wed May 26 18:32:09 2010
@@ -603,13 +603,13 @@
 
     @arguments("jitcode", "boxes")
     def _opimpl_inline_call1(self, jitcode, argboxes):
-        self.metainterp.perform_call(jitcode, argboxes)
+        return self.metainterp.perform_call(jitcode, argboxes)
     @arguments("jitcode", "boxes2")
     def _opimpl_inline_call2(self, jitcode, argboxes):
-        self.metainterp.perform_call(jitcode, argboxes)
+        return self.metainterp.perform_call(jitcode, argboxes)
     @arguments("jitcode", "boxes3")
     def _opimpl_inline_call3(self, jitcode, argboxes):
-        self.metainterp.perform_call(jitcode, argboxes)
+        return self.metainterp.perform_call(jitcode, argboxes)
 
     opimpl_inline_call_r_i = _opimpl_inline_call1
     opimpl_inline_call_r_r = _opimpl_inline_call1
@@ -760,32 +760,6 @@
         self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc)
         return clsbox
 
-    def verify_green_args(self, varargs):
-        num_green_args = self.metainterp.staticdata.num_green_args
-        for i in range(num_green_args):
-            assert isinstance(varargs[i], Const)
-
-##    def blackhole_reached_merge_point(self, varargs):
-##        if self.metainterp.in_recursion:
-##            portal_code = self.metainterp.staticdata.portal_code
-##            # small hack: fish for the result box
-##            lenenv = len(self.env)
-##            raised = self.perform_call(portal_code, varargs)
-##            # in general this cannot be assumed, but when blackholing,
-##            # perform_call returns True only if an exception is called. In
-##            # this case perform_call has called finishframe_exception
-##            # already, so we need to return.
-##            if raised:
-##                return
-##            if lenenv == len(self.env):
-##                res = None
-##            else:
-##                assert lenenv == len(self.env) - 1
-##                res = self.env.pop()
-##            self.metainterp.finishframe(res)
-##        else:
-##            raise self.metainterp.staticdata.ContinueRunningNormally(varargs)
-
     @arguments()
     def opimpl_can_enter_jit(self):
         if self.metainterp.in_recursion:
@@ -795,7 +769,7 @@
 
     @arguments("orgpc", "boxes3", "boxes3")
     def opimpl_jit_merge_point(self, orgpc, greenboxes, redboxes):
-        self.verify_green_args(greenboxes)
+        self.metainterp.verify_green_args(greenboxes)
         # xxx we may disable the following line in some context later
         self.debug_merge_point(greenboxes)
         if self.metainterp.seen_can_enter_jit:
@@ -1022,7 +996,6 @@
         effectinfo = descr.get_extra_info()
         if (effectinfo is None or effectinfo.extraeffect ==
                                 effectinfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE):
-            XXX
             # residual calls require attention to keep virtualizables in-sync
             self.metainterp.vable_and_vrefs_before_residual_call()
             # xxx do something about code duplication
@@ -1030,12 +1003,10 @@
                 rop.CALL_MAY_FORCE, allboxes, descr=descr)
             self.metainterp.vable_and_vrefs_after_residual_call()
             if resbox is not None:
-                self.make_result_box(resbox)
-            self.generate_guard(self.pc, rop.GUARD_NOT_FORCED, None, [])
-            if exc:
-                return self.metainterp.handle_exception()
-            else:
-                return self.metainterp.assert_no_exception()
+                self.make_result_of_lastop(resbox)
+            self.generate_guard(rop.GUARD_NOT_FORCED, None)
+            self.metainterp.handle_possible_exception()
+            return resbox
         else:
             effect = effectinfo.extraeffect
             if effect == effectinfo.EF_CANNOT_RAISE:
@@ -1248,12 +1219,25 @@
     def is_blackholing(self):
         return False       # XXX get rid of this method
 
-    def perform_call(self, jitcode, boxes, greenkey=None):
+    def perform_call(self, jitcode, boxes):
         # causes the metainterp to enter the given subfunction
+        # with a special case for recursive portal calls
+        if jitcode is self.staticdata.portal_code:
+            return self.perform_recursive_call_to_portal(boxes)
+        else:
+            self._perform_call(jitcode, boxes)
+            # ^^^ always raises
+
+    def _perform_call(self, jitcode, boxes, greenkey=None):
         f = self.newframe(jitcode, greenkey)
         f.setup_call(boxes)
         raise ChangeFrame
 
+    def verify_green_args(self, varargs):
+        num_green_args = self.staticdata.num_green_args
+        for i in range(num_green_args):
+            assert isinstance(varargs[i], Const)
+
     def newframe(self, jitcode, greenkey=None):
         if jitcode is self.staticdata.portal_code:
             self.in_recursion += 1
@@ -2014,17 +1998,48 @@
                 max_key = key
         return max_key
 
-    def direct_assembler_call(self, pc, varargs, token, call_position):
+    def perform_recursive_call_to_portal(self, boxes):
+        warmrunnerstate = self.staticdata.state
+        portal_code = self.staticdata.portal_code
+        token = None
+        if not self.is_blackholing() and warmrunnerstate.inlining:
+            num_green_args = self.staticdata.num_green_args
+            greenkey = boxes[:num_green_args]
+            if warmrunnerstate.can_inline_callable(greenkey):
+                return self._perform_call(portal_code, boxes, greenkey)
+            token = warmrunnerstate.get_assembler_token(greenkey)
+        call_position = 0
+        if token is not None:
+            call_position = len(self.history.operations)
+            # verify that we have all green args, needed to make sure
+            # that assembler that we call is still correct
+            self.verify_green_args(boxes)
+        funcbox = ConstInt(llmemory.cast_adr_to_int(portal_code.fnaddr))
+        frame = self.framestack[-1]
+        resbox = frame.do_residual_call(funcbox, portal_code.calldescr, boxes)
+        if token is not None:
+            # XXX fix the call position, <UGLY!>
+            while True:
+                op = self.history.operations[call_position]
+                if op.opnum == rop.CALL or op.opnum == rop.CALL_MAY_FORCE:
+                    break
+                call_position += 1
+            # </UGLY!>
+            # this will substitute the residual call with assembler call
+            self.direct_assembler_call(boxes, token, call_position)
+        return resbox
+
+    def direct_assembler_call(self, boxes, token, call_position):
         """ Generate a direct call to assembler for portal entry point.
         """
         assert not self.is_blackholing() # XXX
         num_green_args = self.staticdata.num_green_args
-        args = varargs[num_green_args + 1:]
+        args = boxes[num_green_args:]
         resbox = self.history.operations[call_position].result
         rest = self.history.slice_history_at(call_position)
         if self.staticdata.virtualizable_info is not None:
             vindex = self.staticdata.virtualizable_info.index_of_virtualizable
-            vbox = args[vindex - num_green_args]
+            vbox = boxes[vindex]
             args += self.gen_load_from_other_virtualizable(vbox)
         self.history.record(rop.CALL_ASSEMBLER, args[:], resbox, descr=token)
         self.history.operations += rest

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_recursive.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_recursive.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_recursive.py	Wed May 26 18:32:09 2010
@@ -24,6 +24,7 @@
                 return 1
         res = self.meta_interp(main, [20], optimizer=OPTIMIZER_SIMPLE)
         assert res == main(20)
+        self.check_history(call=0)
 
     def test_simple_recursion_with_exc(self):
         myjitdriver = JitDriver(greens=[], reds=['n', 'm'])

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/warmspot.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/warmspot.py	Wed May 26 18:32:09 2010
@@ -554,6 +554,7 @@
             self.PTR_PORTAL_FUNCTYPE.TO,
             self.PTR_PORTAL_FUNCTYPE.TO.ARGS,
             self.PTR_PORTAL_FUNCTYPE.TO.RESULT)
+        self.codewriter.setup_portal_runner_ptr(self.portal_runner_ptr)
 
         vinfo = self.metainterp_sd.virtualizable_info
 



More information about the Pypy-commit mailing list