[pypy-svn] r40452 - in pypy/branch/jit-virtual-world/pypy/jit: . hintannotator hintannotator/test timeshifter timeshifter/test

arigo at codespeak.net arigo at codespeak.net
Tue Mar 13 20:42:43 CET 2007


Author: arigo
Date: Tue Mar 13 20:42:39 2007
New Revision: 40452

Modified:
   pypy/branch/jit-virtual-world/pypy/jit/TODO.txt
   pypy/branch/jit-virtual-world/pypy/jit/hintannotator/annotator.py
   pypy/branch/jit-virtual-world/pypy/jit/hintannotator/bookkeeper.py
   pypy/branch/jit-virtual-world/pypy/jit/hintannotator/model.py
   pypy/branch/jit-virtual-world/pypy/jit/hintannotator/test/test_annotator.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/hrtyper.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rtimeshift.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_timeshift.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_vlist.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/transform.py
Log:
(pedronis, arigo)

* a more elegant approach to indirect calls: make a ts stub
  for the functions that shouldn't be looked in.

* timeshift support for green oopspec calls, done by having
  general support for green calls that can raise.


Modified: pypy/branch/jit-virtual-world/pypy/jit/TODO.txt
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/TODO.txt	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/TODO.txt	Tue Mar 13 20:42:39 2007
@@ -36,5 +36,5 @@
 - share code between the machine code backends (MachineCodeBlock,
   possibly register allocation)
 
-- more green vars in the hintannotator: for y=frozen_list[x]
-  and for y=hint(x, deepfreeze=True) if x is green
+- more green vars in the hintannotator: for y=hint(x, deepfreeze=True)
+  if x is green

Modified: pypy/branch/jit-virtual-world/pypy/jit/hintannotator/annotator.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/hintannotator/annotator.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/hintannotator/annotator.py	Tue Mar 13 20:42:39 2007
@@ -20,14 +20,6 @@
     def look_inside_graph(self, graph):
         return True
 
-    def look_inside_graphs(self, graph_list):
-        if not graph_list:
-            return False   # cannot follow indirect call with no known targets
-        for graph in graph_list:
-            if not self.look_inside_graph(graph):
-                return False
-        return True
-
 
 class StopAtXPolicy(HintAnnotatorPolicy):
     """Useful for tests."""

Modified: pypy/branch/jit-virtual-world/pypy/jit/hintannotator/bookkeeper.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/hintannotator/bookkeeper.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/hintannotator/bookkeeper.py	Tue Mar 13 20:42:39 2007
@@ -2,10 +2,12 @@
 from pypy.tool.tls import tlsobject
 from pypy.tool.ansi_print import ansi_log
 from pypy.objspace.flow.model import copygraph, SpaceOperation, Constant
+from pypy.objspace.flow.model import Variable, Block, Link, FunctionGraph
 from pypy.annotation import model as annmodel
 from pypy.rpython.lltypesystem import lltype, lloperation
 from pypy.tool.algo.unionfind import UnionFind
 from pypy.translator.backendopt import graphanalyze
+from pypy.translator.unsimplify import copyvar
 
 TLS = tlsobject()
 
@@ -42,7 +44,10 @@
             return self._cache[key]
         except KeyError:
             bk = self.bookkeeper
-            graph = copygraph(self.origgraph)
+            if bk.annotator.policy.look_inside_graph(self.origgraph):
+                graph = copygraph(self.origgraph)
+            else:
+                graph = self.build_callback_graph(self.origgraph)
             graph.tag = 'timeshifted'
             try:
                 etrafo = bk.annotator.exceptiontransformer
@@ -58,6 +63,20 @@
             log(str(graph))
             return graph
 
+    def build_callback_graph(self, graph):
+        args_v = [copyvar(None, v) for v in graph.getargs()]
+        v_res = copyvar(None, graph.getreturnvar())
+        rtyper = self.bookkeeper.annotator.base_translator.rtyper  # fish
+        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(graph.name, newstartblock)
+        newgraph.getreturnvar().concretetype = v_res.concretetype
+        newstartblock.closeblock(Link([v_res], newgraph.returnblock))
+        return newgraph
+
 
 class TsGraphCallFamily:
     def __init__(self, tsgraph):

Modified: pypy/branch/jit-virtual-world/pypy/jit/hintannotator/model.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/hintannotator/model.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/hintannotator/model.py	Tue Mar 13 20:42:39 2007
@@ -105,16 +105,6 @@
                 deps.append(v)
 
 
-class PureCallOpOriginFlags(CallOpOriginFlags):
-
-    def record_dependencies(self, greenorigindependencies,
-                                  callreturndependencies):
-        OriginFlags.record_dependencies(self, greenorigindependencies,
-                                              callreturndependencies)
-        CallOpOriginFlags.record_dependencies(self, greenorigindependencies,
-                                                    callreturndependencies)
-
-
 class InputArgOriginFlags(OriginFlags):
 
     def __init__(self, bookkeeper, graph, i):
@@ -351,14 +341,11 @@
         args_hs = args_hs[:-1]
         assert hs_graph_list.is_constant()
         graph_list = hs_graph_list.const
+        if graph_list is None:
+            # cannot follow indirect calls to unknown targets
+            return variableoftype(hs_v1.concretetype.TO.RESULT)
 
         bookkeeper = getbookkeeper()
-        if not bookkeeper.annotator.policy.look_inside_graphs(graph_list):
-            # cannot follow
-            return cannot_follow_call(bookkeeper, graph_list,
-                                      (hs_v1,) + args_hs,
-                                      hs_v1.concretetype.TO.RESULT)
-
         myorigin = bookkeeper.myorigin()
         myorigin.__class__ = CallOpOriginFlags     # thud
         fixed = myorigin.read_fixed()
@@ -418,7 +405,7 @@
         if not hasattr(fnobj, 'graph'):
             raise NotImplementedError("XXX call to externals or primitives")
         if not bookkeeper.annotator.policy.look_inside_graph(fnobj.graph):
-            return cannot_follow_call(bookkeeper, [fnobj.graph], args_hs,
+            return cannot_follow_call(bookkeeper, fnobj.graph, args_hs,
                                       lltype.typeOf(fnobj).RESULT)
 
         # recursive call from the entry point to itself: ignore them and
@@ -654,13 +641,17 @@
         # Exception: an operation on a frozen container is constant-foldable.
         RESULT = bookkeeper.current_op_concretetype()
         if '.' in operation_name and args_hs[0].deepfrozen:
-            myorigin = bookkeeper.myorigin()
-            d = newset({myorigin: True}, *[hs_c.origins for hs_c in args_hs])
-            return SomeLLAbstractConstant(RESULT, d,
-                                          eager_concrete = False,   # probably
-                                          myorigin = myorigin)
-        else:
-            return variableoftype(RESULT)
+            for hs_v in args_hs:
+                if not isinstance(hs_v, SomeLLAbstractConstant):
+                    break
+            else:
+                myorigin = bookkeeper.myorigin()
+                d = newset({myorigin: True}, *[hs_c.origins
+                                               for hs_c in args_hs])
+                return SomeLLAbstractConstant(RESULT, d,
+                                              eager_concrete = False,   # probably
+                                              myorigin = myorigin)
+        return variableoftype(RESULT)
 
     # --- the code below is not used any more except by test_annotator.py ---
     if operation_name == 'newlist':
@@ -684,17 +675,9 @@
     hs_result = handler(*args_hs)   # which may raise NotImplementedError
     return hs_result
 
-def cannot_follow_call(bookkeeper, graph_list, args_hs, RESTYPE):
+def cannot_follow_call(bookkeeper, graph, args_hs, RESTYPE):
     # the policy prevents us from following the call
-    if not graph_list:       # no known target, give up
-        return variableoftype(RESTYPE)
-    pure_call = True
-    for graph in graph_list:
-        if not bookkeeper.is_pure_graph(graph):
-            # it's not calling pure graphs either, so the result
-            # is entierely unknown
-            pure_call = False
-            break
+    pure_call = bookkeeper.is_pure_graph(graph)
     # when calling pure graphs, consider the call as an operation.
     for hs in args_hs:
         if not isinstance(hs, SomeLLAbstractConstant):
@@ -707,26 +690,8 @@
         h_res = SomeLLAbstractConstant(RESTYPE, d,
                                        eager_concrete = False,   # probably
                                        myorigin = myorigin)
-        fixed = myorigin.read_fixed()
     else:
         h_res = variableoftype(RESTYPE)
-        fixed = False
-
-    look_inside_graph = bookkeeper.annotator.policy.look_inside_graph
-    followable_graphs = [graph for graph in graph_list
-                               if look_inside_graph(graph)]
-    if followable_graphs:
-        # we can still follow this graph, even if we cannot follow all of them
-        tsgraphs_accum = []
-        bookkeeper.graph_family_call(followable_graphs, fixed, args_hs[1:],
-                                     tsgraphs_accum)
-        myorigin = bookkeeper.myorigin()
-        myorigin.any_called_graph = tsgraphs_accum[0]
-        if pure_call:
-            myorigin.__class__ = PureCallOpOriginFlags     # thud
-        else:
-            myorigin.__class__ = CallOpOriginFlags     # thud
-
     return h_res
 
 # ____________________________________________________________

Modified: pypy/branch/jit-virtual-world/pypy/jit/hintannotator/test/test_annotator.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/hintannotator/test/test_annotator.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/hintannotator/test/test_annotator.py	Tue Mar 13 20:42:39 2007
@@ -818,6 +818,7 @@
         return h(x)
 
     P = StopAtXPolicy(h1)
+    P.oopspec = True
     P.entrypoint_returns_red = False
     hs, hannotator = hannotate(f, [int, int], policy=P, annotator=True)
     assert not hs.is_green()
@@ -841,6 +842,7 @@
         return z
 
     P = StopAtXPolicy(h1)
+    P.oopspec = True
     P.entrypoint_returns_red = False
     hs, hannotator = hannotate(f, [int, int], policy=P, annotator=True)
     assert hs.is_green()

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/hrtyper.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/hrtyper.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/hrtyper.py	Tue Mar 13 20:42:39 2007
@@ -1321,9 +1321,33 @@
         for r_arg in hop.args_r:
             assert isinstance(r_arg, GreenRepr)
         assert isinstance(hop.r_result, GreenRepr)
+
+        FUNC = hop.args_v[0].concretetype
+        calldesc = rtimeshift.CallDesc(self.RGenOp, FUNC.TO)
+        args_v = hop.args_v
+        args_s = [annmodel.lltype_to_annotation(v.concretetype)
+                  for v in args_v]
+        s_result = annmodel.lltype_to_annotation(FUNC.TO.RESULT)
+        v_jitstate = hop.llops.getjitstate()
+        return hop.llops.genmixlevelhelpercall(calldesc.green_call,
+                                               [self.s_JITState] + args_s,
+                                               [v_jitstate     ] + args_v,
+                                               s_result)
+
+    def translate_op_green_call_noexc(self, hop):
+        for r_arg in hop.args_r:
+            assert isinstance(r_arg, GreenRepr)
+        assert isinstance(hop.r_result, GreenRepr)
         v = hop.genop('direct_call', hop.args_v, hop.r_result.lowleveltype)
         return v
 
+    def translate_op_green_indirect_call_noexc(self, hop):
+        for r_arg in hop.args_r[:-1]:
+            assert isinstance(r_arg, GreenRepr)
+        assert isinstance(hop.r_result, GreenRepr)
+        v = hop.genop('indirect_call', hop.args_v, hop.r_result.lowleveltype)
+        return v
+
     def translate_op_red_call(self, hop):
         bk = self.annotator.bookkeeper
         v_jitstate = hop.llops.getjitstate()

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rtimeshift.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rtimeshift.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rtimeshift.py	Tue Mar 13 20:42:39 2007
@@ -500,6 +500,15 @@
         self.result_kind = RGenOp.kindToken(FUNCTYPE.RESULT)
         # xxx what if the result is virtualizable?
         self.redboxbuilder = rvalue.ll_redboxbuilder(FUNCTYPE.RESULT)
+        whatever_return_value = FUNCTYPE.RESULT._defl()
+        def green_call(jitstate, fnptr, *args):
+            try:
+                result = fnptr(*args)
+            except Exception, e:
+                jitstate.residual_exception(e)
+                result = whatever_return_value
+            return result
+        self.green_call = green_call
 
     def _freeze_(self):
         return True
@@ -532,6 +541,7 @@
             else:
                 gv_flags = builder.genop2("int_or", gv_flags, gv_flag)
         else:
+            assert gv_flags is None
             exceptiondesc.fetch_global_excdata(jitstate)
     if gv_flags is None:
         gv_flags = builder.rgenop.constPrebuiltGlobal(0)

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_timeshift.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_timeshift.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_timeshift.py	Tue Mar 13 20:42:39 2007
@@ -1,6 +1,7 @@
 import py
 from pypy.translator.translator import TranslationContext, graphof
 from pypy.jit.hintannotator.annotator import HintAnnotator, HintAnnotatorPolicy
+from pypy.jit.hintannotator.annotator import StopAtXPolicy
 from pypy.jit.hintannotator.bookkeeper import HintBookkeeper
 from pypy.jit.hintannotator.model import *
 from pypy.jit.timeshifter.hrtyper import HintRTyper, originalconcretetype
@@ -348,21 +349,6 @@
         assert count == expected_count
 
 
-class StopAtXPolicy(HintAnnotatorPolicy):
-    def __init__(self, *funcs):
-        HintAnnotatorPolicy.__init__(self, novirtualcontainer=True,
-                                     oopspec=True)
-        self.funcs = funcs
-
-    def look_inside_graph(self, graph):
-        try:
-            if graph.func in self.funcs:
-                return False
-        except AttributeError:
-            pass
-        return True
-
-
 class TestTimeshift(TimeshiftingTests):
 
     def test_simple_fixed(self):
@@ -1466,22 +1452,47 @@
         assert res == f(4,113)
         self.check_insns({'int_sub': 1})
 
-    def test_indirect_sometimes_residual_red_call(self):
-        py.test.skip("in-progress")
+    def test_indirect_sometimes_residual_pure_red_call(self):
         def h1(x):
             return x-2
         def h2(x):
             return x*4
         l = [h1, h2]
         def f(n, x):
+            hint(None, global_merge_point=True)
+            hint(n, concrete=True)
             frozenl = hint(l, deepfreeze=True)
             h = frozenl[n&1]
             return h(x)
 
         P = StopAtXPolicy(h1)
-        res = self.timeshift(f, [7, 3], [0], policy=P)
+        P.oopspec = True
+        res = self.timeshift(f, [7, 3], [], policy=P)
         assert res == f(7,3)
         self.check_insns({'int_mul': 1})
-        res = self.timeshift(f, [4, 113], [0], policy=P)
+        res = self.timeshift(f, [4, 113], [], policy=P)
         assert res == f(4,113)
         self.check_insns({'direct_call': 1})
+
+    def test_indirect_sometimes_residual_pure_but_fixed_red_call(self):
+        def h1(x):
+            return x-2
+        def h2(x):
+            return x*4
+        l = [h1, h2]
+        def f(n, x):
+            hint(None, global_merge_point=True)
+            frozenl = hint(l, deepfreeze=True)
+            h = frozenl[n&1]
+            z = h(x)
+            hint(z, concrete=True)
+            return z
+
+        P = StopAtXPolicy(h1)
+        P.oopspec = True
+        res = self.timeshift(f, [7, 3], [], policy=P)
+        assert res == f(7,3)
+        self.check_insns({})
+        res = self.timeshift(f, [4, 113], [], policy=P)
+        assert res == f(4,113)
+        self.check_insns({})

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_vlist.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_vlist.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_vlist.py	Tue Mar 13 20:42:39 2007
@@ -129,3 +129,30 @@
         res = self.timeshift(ll_function, [3, 4], [0, 1], policy=P_OOPSPEC)
         assert res == 5
         self.check_insns({})
+
+    def test_frozen_list(self):
+        lst = [5, 7, 9]
+        def ll_function(x):
+            mylist = hint(lst, deepfreeze=True)
+            z = mylist[x]
+            hint(z, concrete=True)
+            return z
+
+        res = self.timeshift(ll_function, [1], policy=P_OOPSPEC)
+        assert res == 7
+        self.check_insns({})
+
+    def test_frozen_list_indexerror(self):
+        lst = [5, 7, 9]
+        def ll_function(x):
+            mylist = hint(lst, deepfreeze=True)
+            try:
+                z = mylist[x]
+            except IndexError:
+                return -42
+            hint(z, concrete=True)
+            return z
+
+        res = self.timeshift(ll_function, [4], policy=P_OOPSPEC)
+        assert res == -42
+        self.check_insns({})

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/transform.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/transform.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/transform.py	Tue Mar 13 20:42:39 2007
@@ -492,11 +492,19 @@
             args_v = spaceop.args[1:]
         elif spaceop.opname == 'indirect_call':
             graphs = spaceop.args[-1].value
+            if graphs is None:
+                return     # cannot follow at all
             args_v = spaceop.args[1:-1]
         else:
             raise AssertionError(spaceop.opname)
-        if not self.hannotator.policy.look_inside_graphs(graphs):
-            return    # cannot follow this call
+        # if the graph - or all the called graphs - are marked as "don't
+        # follow", directly return None as a special case.  (This is only
+        # an optimization for the indirect_call case.)
+        for graph in graphs:
+            if self.hannotator.policy.look_inside_graph(graph):
+                break
+        else:
+            return
         for graph in graphs:
             tsgraph = self.timeshifted_graph_of(graph, args_v, spaceop.result)
             yield graph, tsgraph
@@ -511,6 +519,10 @@
                 self.hannotator.policy.oopspec):
                 if fnobj._callable.oopspec.startswith('vable.'):
                     return 'vable', None
+                hs_result = self.hannotator.binding(spaceop.result)
+                if (hs_result.is_green() and
+                    hs_result.concretetype is not lltype.Void):
+                    return 'green', self.can_raise(spaceop)
                 return 'oopspec', self.can_raise(spaceop)
         if self.hannotator.bookkeeper.is_green_call(spaceop):
             return 'green', None
@@ -726,12 +738,20 @@
         op.opname = 'rpyexc_raise'
         op.args = op.args[1:]
 
-    def handle_green_call(self, block, pos):
-        # green-returning call, for now (XXX) we assume it's an
-        # all-green function that we can just call
+    def handle_green_call(self, block, pos, withexc=False):
+        # an all-green function that we can just call
         op = block.operations[pos]
-        assert op.opname == 'direct_call'
-        op.opname = 'green_call'
+        if op.opname == 'indirect_call':
+            if withexc:
+                op.args.pop()    # remove the graph list
+                op.opname = 'green_call'
+            else:
+                op.opname = 'green_indirect_call_noexc'
+        else:
+            if withexc:
+                op.opname = 'green_call'
+            else:
+                op.opname = 'green_call_noexc'
 
     def handle_yellow_call(self, block, pos, withexc):
         self.handle_red_call(block, pos, color='yellow', withexc=withexc)
@@ -804,6 +824,8 @@
         else:
             promoteblock = block
             v_flags2 = v_flags
+        # if there is no global merge point, this 'promote' will actually
+        # always see a constant red box
         v_finished_flag = self.genop(promoteblock, 'promote', [v_flags2],
                                      resulttype = lltype.Bool)
         self.go_to_dispatcher_if(promoteblock, v_finished_flag)



More information about the Pypy-commit mailing list