[pypy-svn] r62138 - in pypy/branch/pyjitpl5/pypy/jit/metainterp: . test

arigo at codespeak.net arigo at codespeak.net
Wed Feb 25 14:25:22 CET 2009


Author: arigo
Date: Wed Feb 25 14:25:20 2009
New Revision: 62138

Modified:
   pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/policy.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_basic.py
Log:
Test and fix for cases where the policy decides that, in an
indirect_call, some of the called graphs must be seen but
others not.


Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py	Wed Feb 25 14:25:20 2009
@@ -210,9 +210,11 @@
     def __init__(self, codewriter, graph, portal):
         self.codewriter = codewriter
         self.cpu = codewriter.metainterp.cpu
-        self.graph = graph
         self.portal = portal
-        self.bytecode = self.codewriter.get_jitcode(self.graph)
+        self.bytecode = self.codewriter.get_jitcode(graph)
+        if not codewriter.policy.look_inside_graph(graph):
+            graph = make_calling_stub(codewriter.rtyper, graph)
+        self.graph = graph
 
     def assemble(self):
         """Assemble the opcodes for self.bytecode."""
@@ -620,11 +622,11 @@
     #    return getattr(self, 'handle_%s_call' % color)(op)
 
     def serialize_op_direct_call(self, op):
-        self.minimize_variables()
         color = self.codewriter.policy.guess_call_kind(op)
         return getattr(self, 'handle_%s_call' % color)(op)
 
     def handle_regular_call(self, op):
+        self.minimize_variables()
         [targetgraph] = self.codewriter.policy.graphs_from(op)
         jitbox = self.codewriter.get_jitcode(targetgraph)
         self.emit('call')
@@ -633,15 +635,8 @@
                            if x.concretetype is not lltype.Void])
         self.register_var(op.result)
 
-#     def handle_green_call(self, op):
-#         assert op.result.concretetype is not lltype.Void
-#         self.emit('green_call_%s' % getkind_num(self.cpu,
-#                                                 op.result.concretetype))
-#         self.emit_varargs([x for x in op.args
-#                              if x.concretetype is not lltype.Void])
-#         self.register_var(op.result)
-
     def handle_residual_call(self, op):
+        self.minimize_variables()
         self.emit('residual_call_%s' % getkind_num(self.cpu,
                                                    op.result.concretetype))
         self.emit_varargs([x for x in op.args
@@ -689,28 +684,6 @@
         self.emit_varargs([c_func] + args)
         self.register_var(op.result)
 
-#     def serialize_op_indirect_call(self, op):
-#         xxx
-#         color = support.guess_call_kind(self.codewriter.hannotator, op)
-#         return getattr(self, 'handle_%s_indirect_call' % color)(op)
-
-#     def handle_red_indirect_call(self, op):
-#         # indirect_call to a red function pointer
-#         # XXX for now, this is handled as a residual call
-#         self.handle_residual_indirect_call(op)
-
-#     def handle_direct_indirect_call(self, op):
-#         # indirect_call to a green function pointer
-#         self.minimize_variables()
-#         targets = support.graphs_from(self.codewriter.hannotator, op)
-#         indirectcallset = self.codewriter.get_indirectcallset(targets)
-#         self.emit('direct_indirect_call')
-#         self.emit(self.get_position(indirectcallset))
-#         self.emit(self.var_position(op.args[0]))
-#         self.emit_varargs([x for x in op.args[1:-1]
-#                              if x.concretetype is not lltype.Void])
-#         self.register_var(op.result)
-
     def serialize_op_indirect_call(self, op):
         self.minimize_variables()
         targets = self.codewriter.policy.graphs_from(op)
@@ -840,3 +813,23 @@
             result[i + 1] = chr((index >>  8) & 0xff)
             result[i + 2] = chr(index & 0xff)
     return "".join(result)
+
+# ____________________________________________________________
+
+def make_calling_stub(rtyper, graph):
+    from pypy.objspace.flow.model import Block, Link, FunctionGraph
+    from pypy.objspace.flow.model import SpaceOperation
+    from pypy.translator.unsimplify import copyvar
+    #
+    args_v = [copyvar(None, v) for v in graph.getargs()]
+    v_res = copyvar(None, graph.getreturnvar())
+    fnptr = rtyper.getcallable(graph)
+    v_ptr = Constant(fnptr, lltype.typeOf(fnptr))
+    newstartblock = Block(args_v)
+    newstartblock.operations.append(
+        SpaceOperation('direct_call', [v_ptr] + args_v, v_res))
+    newgraph = FunctionGraph('%s_ts_stub' % (graph.name,), newstartblock)
+    newgraph.getreturnvar().concretetype = v_res.concretetype
+    newstartblock.closeblock(Link([v_res], newgraph.returnblock))
+    newgraph.ts_stub_for = graph
+    return newgraph

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/policy.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/policy.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/policy.py	Wed Feb 25 14:25:20 2009
@@ -1,14 +1,32 @@
 
-class JitPolicy:
+class JitPolicy(object):
+
+    def look_inside_function(self, func):
+        # explicitly pure functions are always opaque
+        if getattr(func, '_pure_function_', False):
+            return False
+        return True
+
+    def look_inside_graph(self, graph):
+        try:
+            func = graph.func
+        except AttributeError:
+            return True
+        return self.look_inside_function(func)
+
     def graphs_from(self, op):
         if op.opname == 'direct_call':
             graph = op.args[0].value._obj.graph
-            # explicitly pure functions are always opaque
-            if getattr(getattr(graph, 'func', None), '_pure_function_', False):
-                return None
-            return [graph]
-        assert op.opname == 'indirect_call'
-        return op.args[-1].value
+            if self.look_inside_graph(graph):
+                return [graph]     # common case: look inside this graph
+        else:
+            assert op.opname == 'indirect_call'
+            graphs = op.args[-1].value
+            for graph in graphs:
+                if self.look_inside_graph(graph):
+                    return graphs  # common case: look inside at least 1 graph
+        # residual call case: we don't need to look into any graph
+        return None
 
     def guess_call_kind(self, op):
         targetgraphs = self.graphs_from(op)
@@ -26,11 +44,7 @@
     def __init__(self, *funcs):
         self.funcs = funcs
 
-    def graphs_from(self, op):
-        graphs = JitPolicy.graphs_from(self, op)
-        if graphs is None or len(graphs) > 1: # XXX a hack
-            return graphs
-        [graph] = graphs
-        if getattr(graph, 'func', None) in self.funcs:
-            return None
-        return [graph]
+    def look_inside_function(self, func):
+        if func in self.funcs:
+            return False
+        return super(StopAtXPolicy, self).look_inside_function(func)

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_basic.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_basic.py	Wed Feb 25 14:25:20 2009
@@ -179,6 +179,28 @@
         res = self.meta_interp(f, [31])
         assert res == -4
 
+    def test_stopatxpolicy(self):
+        myjitdriver = JitDriver(greens = [], reds = ['y'])
+        def internfn(y):
+            return y * 3
+        def externfn(y):
+            return y % 4
+        def f(y):
+            while y >= 0:
+                myjitdriver.can_enter_jit(y=y)
+                myjitdriver.jit_merge_point(y=y)
+                if y & 7:
+                    f = internfn
+                else:
+                    f = externfn
+                f(y)
+                y -= 1
+            return 42
+        policy = StopAtXPolicy(externfn)
+        res = self.meta_interp(f, [31], policy=policy)
+        assert res == 42
+        self.check_loops(int_mul=1, int_mod=0)
+
 
 class TestOOtype(BasicTests, OOJitMixin):
     pass



More information about the Pypy-commit mailing list