[pypy-svn] r32683 - in pypy/branch/jit-promotion: . pypy/jit/codegen pypy/jit/codegen/llgraph pypy/jit/hintannotator pypy/jit/timeshifter pypy/jit/timeshifter/test pypy/rpython pypy/rpython/lltypesystem pypy/rpython/test

arigo at codespeak.net arigo at codespeak.net
Wed Sep 27 21:21:53 CEST 2006


Author: arigo
Date: Wed Sep 27 21:21:50 2006
New Revision: 32683

Added:
   pypy/branch/jit-promotion/
      - copied from r32681, pypy/dist/
   pypy/branch/jit-promotion/pypy/jit/timeshifter/test/test_promotion.py   (contents, props changed)
   pypy/branch/jit-promotion/pypy/rpython/annlowlevel.py
      - copied unchanged from r32682, pypy/dist/pypy/rpython/annlowlevel.py
   pypy/branch/jit-promotion/pypy/rpython/rmodel.py
      - copied unchanged from r32682, pypy/dist/pypy/rpython/rmodel.py
   pypy/branch/jit-promotion/pypy/rpython/test/test_llann.py
      - copied unchanged from r32682, pypy/dist/pypy/rpython/test/test_llann.py
Modified:
   pypy/branch/jit-promotion/pypy/jit/codegen/llgraph/llimpl.py
   pypy/branch/jit-promotion/pypy/jit/codegen/llgraph/rgenop.py
   pypy/branch/jit-promotion/pypy/jit/codegen/model.py
   pypy/branch/jit-promotion/pypy/jit/hintannotator/model.py
   pypy/branch/jit-promotion/pypy/jit/timeshifter/rcontainer.py
   pypy/branch/jit-promotion/pypy/jit/timeshifter/rtimeshift.py
   pypy/branch/jit-promotion/pypy/jit/timeshifter/rtyper.py
   pypy/branch/jit-promotion/pypy/jit/timeshifter/rvalue.py
   pypy/branch/jit-promotion/pypy/jit/timeshifter/test/test_timeshift.py
   pypy/branch/jit-promotion/pypy/jit/timeshifter/transform.py
   pypy/branch/jit-promotion/pypy/rpython/lltypesystem/lloperation.py
Log:
(arre, pedronis, arigo)

Intermediate check-in to share this big batch of changes: see
test_promotion for the goal.



Modified: pypy/branch/jit-promotion/pypy/jit/codegen/llgraph/llimpl.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/llgraph/llimpl.py	(original)
+++ pypy/branch/jit-promotion/pypy/jit/codegen/llgraph/llimpl.py	Wed Sep 27 21:21:50 2006
@@ -125,14 +125,15 @@
     result = op.fold(*examples)
     return lltype.typeOf(result)
 
-def gencallableconst(name, targetcontainer, gv_FUNCTYPE):
+def gencallableconst(name, targetcontainer, returncontainer, gv_FUNCTYPE):
     # 'name' is just a way to track things
     if not isinstance(name, str):
         name = LLSupport.from_rstr(name)
     target = from_opaque_object(targetcontainer.obj)
+    returnblock = from_opaque_object(returncontainer.obj)
     FUNCTYPE = from_opaque_object(gv_FUNCTYPE).value
     fptr = lltype.functionptr(FUNCTYPE, name,
-                              graph=_buildgraph(target, FUNCTYPE))
+                              graph=_buildgraph(target, returnblock, FUNCTYPE))
     return genconst(fptr)
 
 def genconst(llvalue):
@@ -202,6 +203,29 @@
     return pseudotuple(to_opaque_object(false_link),
                        to_opaque_object(true_link))
 
+def closeblockswitch(blockcontainer, exitswitch):
+    block = from_opaque_object(blockcontainer.obj)
+    exitswitch = from_opaque_object(exitswitch)
+    assert isinstance(exitswitch, flowmodel.Variable)
+    block.exitswitch = exitswitch
+    default_link = flowmodel.Link([], None)
+    default_link.exitcase = "default"
+    default_link.llexitcase = None
+    block.closeblock(default_link)
+    return to_opaque_object(default_link)
+
+def add_case(blockcontainer, exitcase):
+    block = from_opaque_object(blockcontainer.obj)
+    exitcase = from_opaque_object(exitcase)
+    assert isinstance(exitcase, flowmodel.Constant)
+    assert isinstance(block.exitswitch, Variable)
+    case_link = flowmodel.Link([], None)
+    case_link.exitcase = exitcase.value
+    case_link.llexitcase = exitcase.value
+    exits = block.exits[:-1] + (case_link,) + block.exits[-1:]
+    block.recloseblock(*exits)
+    return to_opaque_object(case_link)
+
 class pseudotuple(object):
     # something that looks both like a hl and a ll tuple
     def __init__(self, *items):
@@ -239,32 +263,32 @@
     vars = _inputvars(vars)
     _closelink(link, vars, targetblock)
 
-def closereturnlink(link, returnvar):
-    returnvar = from_opaque_object(returnvar)
-    link = from_opaque_object(link)
-    v = flowmodel.Variable()
-    v.concretetype = returnvar.concretetype
-    pseudoreturnblock = flowmodel.Block([v])
-    pseudoreturnblock.operations = ()
-    _closelink(link, [returnvar], pseudoreturnblock)
-
-def _patchgraph(graph, RESULT):
-    returntype = None
-    links = []
-    for link in graph.iterlinks():
-        if link.target.operations == ():
-            assert len(link.args) == 1    # for now
-            if returntype is None:
-                returntype = link.target.inputargs[0].concretetype
-            else:
-                assert returntype == link.target.inputargs[0].concretetype
-            links.append(link)
-    if returntype is None:
-        returntype = lltype.Void
-    graph.returnblock.inputargs[0].concretetype = RESULT
-    targetblock = casting_bridge([returntype], [RESULT], graph.returnblock)
-    for link in links:
-        link.target = targetblock
+##def closereturnlink(link, returnvar):
+##    returnvar = from_opaque_object(returnvar)
+##    link = from_opaque_object(link)
+##    v = flowmodel.Variable()
+##    v.concretetype = returnvar.concretetype
+##    pseudoreturnblock = flowmodel.Block([v])
+##    pseudoreturnblock.operations = ()
+##    _closelink(link, [returnvar], pseudoreturnblock)
+
+##def _patchgraph(graph, RESULT):
+##    returntype = None
+##    links = []
+##    for link in graph.iterlinks():
+##        if link.target.operations == ():
+##            assert len(link.args) == 1    # for now
+##            if returntype is None:
+##                returntype = link.target.inputargs[0].concretetype
+##            else:
+##                assert returntype == link.target.inputargs[0].concretetype
+##            links.append(link)
+##    if returntype is None:
+##        returntype = lltype.Void
+##    graph.returnblock.inputargs[0].concretetype = RESULT
+##    targetblock = casting_bridge([returntype], [RESULT], graph.returnblock)
+##    for link in links:
+##        link.target = targetblock
 
 class PseudoRTyper(object):
     def __init__(self):
@@ -297,20 +321,28 @@
     else:
         return target
         
-def _buildgraph(block, FUNCTYPE):
+def _buildgraph(block, existingreturnblock, FUNCTYPE):
     ARGS = [v.concretetype for v in block.inputargs]
     startblock =casting_bridge(FUNCTYPE.ARGS, ARGS, block)
     graph = flowmodel.FunctionGraph('generated', startblock)
-    _patchgraph(graph, FUNCTYPE.RESULT)
+
+    returntype = existingreturnblock.inputargs[0].concretetype
+    RESULT = FUNCTYPE.RESULT
+    graph.returnblock.inputargs[0].concretetype = RESULT
+    prereturnblock = casting_bridge([returntype], [RESULT], graph.returnblock)
+    existingreturnblock.closeblock(flowmodel.Link(
+        [existingreturnblock.inputargs[0]],
+        prereturnblock))
     flowmodel.checkgraph(graph)
     eliminate_empty_blocks(graph)
     join_blocks(graph)
     graph.rgenop = True
     return graph
 
-def buildgraph(blockcontainer, FUNCTYPE):
+def buildgraph(blockcontainer, returncontainer, FUNCTYPE):
     block = from_opaque_object(blockcontainer.obj)
-    return _buildgraph(block, FUNCTYPE)
+    returnblock = from_opaque_object(returncontainer.obj)
+    return _buildgraph(block, returnblock, FUNCTYPE)
 
 def testgengraph(gengraph, args, viewbefore=False, executor=LLInterpreter):
     if viewbefore:
@@ -318,9 +350,9 @@
     llinterp = executor(PseudoRTyper())
     return llinterp.eval_graph(gengraph, args)
     
-def runblock(blockcontainer, FUNCTYPE, args,
+def runblock(blockcontainer, returncontainer, FUNCTYPE, args,
              viewbefore=False, executor=LLInterpreter):
-    graph = buildgraph(blockcontainer, FUNCTYPE)
+    graph = buildgraph(blockcontainer, returncontainer, FUNCTYPE)
     return testgengraph(graph, args, viewbefore, executor)
 
 # ____________________________________________________________
@@ -396,8 +428,10 @@
 setannotation(isconst, annmodel.SomeBool())
 setannotation(closeblock1, s_Link)
 setannotation(closeblock2, s_LinkPair)
+setannotation(closeblockswitch, s_Link)
+setannotation(add_case, s_Link)
 setannotation(closelink, None)
-setannotation(closereturnlink, None)
+#setannotation(closereturnlink, None)
 
 setannotation(isptrtype, annmodel.SomeBool())
 

Modified: pypy/branch/jit-promotion/pypy/jit/codegen/llgraph/rgenop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/llgraph/rgenop.py	(original)
+++ pypy/branch/jit-promotion/pypy/jit/codegen/llgraph/rgenop.py	Wed Sep 27 21:21:50 2006
@@ -1,7 +1,7 @@
 from pypy.rpython.objectmodel import specialize
 from pypy.rpython.lltypesystem import lltype
 from pypy.jit.codegen.model import AbstractRGenOp, CodeGenBlock, CodeGenerator
-from pypy.jit.codegen.model import GenVar, GenConst
+from pypy.jit.codegen.model import GenVar, GenConst, CodeGenSwitch
 from pypy.jit.codegen.llgraph import llimpl
 from pypy.rpython.lltypesystem.rclass import fishllattr
 
@@ -30,14 +30,29 @@
 
 
 class LLBlock(CodeGenBlock):
-    def __init__(self, b):
+    def __init__(self, b, g):
         self.b = b
+        self.g = g
+
+class LLFlexSwitch(CodeGenSwitch):
+    
+    def __init__(self, b, g):
+        self.b = b
+        self.g = g
+
+    def add_case(self, gv_case):
+        l_case = llimpl.add_case(self.b, gv_case.v)
+        builder = LLBuilder(self.g)
+        builder.lnk = l_case
+        return builder
+
 
 class LLBuilder(CodeGenerator):
     lnk = llimpl.nulllink
 
-    def __init__(self):
+    def __init__(self, g):
         self.rgenop = rgenop
+        self.g = g
 
     @specialize.arg(1)
     def genop1(self, opname, gv_arg):
@@ -114,7 +129,7 @@
         llimpl.closelink(lnk, args_gv, self.b)
         for i in range(len(args_gv)):
             args_gv[i] = newb_args_gv[i]
-        return LLBlock(self.b)
+        return LLBlock(self.b, self.g)
 
     def finish_and_goto(self, args_gv, targetblock):
         lnk = self.lnk or llimpl.closeblock1(self.b)
@@ -122,15 +137,13 @@
         llimpl.closelink(lnk, args_gv, targetblock.b)
 
     def finish_and_return(self, sigtoken, gv_returnvar):
-        lnk = self.lnk or llimpl.closeblock1(self.b)
-        self.lnk = llimpl.nulllink
-        llimpl.closereturnlink(lnk,
-                               (gv_returnvar or gv_dummy_placeholder).v)
+        gv_returnvar = gv_returnvar or gv_dummy_placeholder
+        self.finish_and_goto([gv_returnvar], LLBlock(self.g, self.g))
 
     def jump_if_true(self, gv_cond):
         l_false, l_true = llimpl.closeblock2(self.b, gv_cond.v)
         self.b = llimpl.nullblock
-        later_builder = LLBuilder()
+        later_builder = LLBuilder(self.g)
         later_builder.lnk = l_true
         self.lnk = l_false
         return later_builder
@@ -138,24 +151,35 @@
     def jump_if_false(self, gv_cond):
         l_false, l_true = llimpl.closeblock2(self.b, gv_cond.v)
         self.b = llimpl.nullblock
-        later_builder = LLBuilder()
+        later_builder = LLBuilder(self.g)
         later_builder.lnk = l_false
         self.lnk = l_true
         return later_builder
 
+    def flexswitch(self, gv_switchvar):
+        l_default = llimpl.closeblockswitch(self.b, gv_switchvar.v)
+        flexswitch = LLFlexSwitch(self.b, self.g)
+        self.b = llimpl.nullblock
+        self.lnk = l_default
+        return flexswitch
+
 
 class RGenOp(AbstractRGenOp):
     gv_Void = gv_Void
 
 
     def newgraph(self, (ARGS_gv, gv_RESULT, gv_FUNCTYPE)):
-        builder = LLBuilder()
+        returnblock = llimpl.newblock()
+        llimpl.geninputarg(returnblock, gv_RESULT.v)
+        g = returnblock   # for now
+        builder = LLBuilder(g)
         inputargs_gv = builder._newblock(ARGS_gv)
-        return builder, LLBlock(builder.b), inputargs_gv
+        return builder, LLBlock(builder.b, builder.g), inputargs_gv
 
     def gencallableconst(self, (ARGS_gv, gv_RESULT, gv_FUNCTYPE), name,
                          entrypoint):
         return LLConst(llimpl.gencallableconst(name, entrypoint.b,
+                                               entrypoint.g,
                                                gv_FUNCTYPE.v))
 
     @staticmethod
@@ -201,6 +225,11 @@
 
     constPrebuiltGlobal = genconst
 
+    def replay(self, block, kinds):
+        builder = LLBuilder(block.g)
+        args_gv = builder._newblock(kinds)
+        return builder, args_gv
+
     # not RPython, just for debugging.  Specific to llgraph.
     @staticmethod
     def reveal(gv):
@@ -210,15 +239,6 @@
             v = fishllattr(gv, 'v')
         return llimpl.reveal(v)
 
-    # Builds a real flow.model.FunctionGraph. Specific to llgraph.
-    @staticmethod
-    def buildgraph(block, FUNCTYPE):
-        if hasattr(block, 'b'):
-            b = block.b
-        else:
-            b = fishllattr(block, 'b')
-        return llimpl.buildgraph(b, FUNCTYPE)
-
     def _freeze_(self):
         return True    # no real point in using a full class in llgraph
 

Modified: pypy/branch/jit-promotion/pypy/jit/codegen/model.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/model.py	(original)
+++ pypy/branch/jit-promotion/pypy/jit/codegen/model.py	Wed Sep 27 21:21:50 2006
@@ -23,3 +23,7 @@
 
 class AbstractRGenOp(object):
     pass
+
+
+class CodeGenSwitch(object):
+    pass

Modified: pypy/branch/jit-promotion/pypy/jit/hintannotator/model.py
==============================================================================
--- pypy/dist/pypy/jit/hintannotator/model.py	(original)
+++ pypy/branch/jit-promotion/pypy/jit/hintannotator/model.py	Wed Sep 27 21:21:50 2006
@@ -258,6 +258,10 @@
             # turn a variable to a constant
             origin = getbookkeeper().myorigin()
             return SomeLLAbstractConstant(hs_v1.concretetype, {origin: True})
+        if hs_flags.const.get('promote', False):
+            hs_concrete = SomeLLAbstractConstant(hs_v1.concretetype, {})
+            hs_concrete.eager_concrete = True
+            return hs_concrete 
 
     def getfield(hs_v1, hs_fieldname):
         S = hs_v1.concretetype.TO
@@ -311,8 +315,6 @@
         return hs_c1
 
     def hint(hs_c1, hs_flags):
-        if hs_flags.const.get('variable', False): # only for testing purposes!!!
-            return SomeLLAbstractVariable(hs_c1.concretetype)
         if hs_flags.const.get('concrete', False):
             for o in hs_c1.origins:
                 o.set_fixed()
@@ -322,6 +324,7 @@
         if hs_flags.const.get('forget', False):
             assert isinstance(hs_c1, SomeLLAbstractConstant)
             return reorigin(hs_c1)
+        return SomeLLAbstractValue.hint(hs_c1, hs_flags)
 
     def direct_call(hs_f1, *args_hs):
         bookkeeper = getbookkeeper()

Modified: pypy/branch/jit-promotion/pypy/jit/timeshifter/rcontainer.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rcontainer.py	(original)
+++ pypy/branch/jit-promotion/pypy/jit/timeshifter/rcontainer.py	Wed Sep 27 21:21:50 2006
@@ -1,5 +1,6 @@
 import operator
 from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.annlowlevel import cachedtype
 from pypy.jit.timeshifter import rvalue
 
 class AbstractContainer(object):
@@ -14,27 +15,8 @@
     def op_getsubstruct(self, jitstate, fielddesc):
         raise NotImplementedError
 
-
 # ____________________________________________________________
 
-class cachedtype(type):
-    """Metaclass for classes that should only have one instance per
-    tuple of arguments given to the constructor."""
-
-    def __init__(selfcls, name, bases, dict):
-        super(cachedtype, selfcls).__init__(name, bases, dict)
-        selfcls._instancecache = {}
-
-    def __call__(selfcls, *args):
-        d = selfcls._instancecache
-        try:
-            return d[args]
-        except KeyError:
-            instance = d[args] = selfcls.__new__(selfcls, *args)
-            instance.__init__(*args)
-            return instance
-
-
 class StructTypeDesc(object):
     __metaclass__ = cachedtype
     firstsubstructdesc = None

Modified: pypy/branch/jit-promotion/pypy/jit/timeshifter/rtimeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtimeshift.py	(original)
+++ pypy/branch/jit-promotion/pypy/jit/timeshifter/rtimeshift.py	Wed Sep 27 21:21:50 2006
@@ -1,8 +1,12 @@
 import operator, weakref
+from pypy.annotation import model as annmodel
 from pypy.rpython.lltypesystem import lltype, lloperation, llmemory
 from pypy.jit.hintannotator.model import originalconcretetype
 from pypy.jit.timeshifter import rvalue
 from pypy.rpython.unroll import unrolling_iterable
+from pypy.rpython.annlowlevel import cachedtype, base_ptr_lltype
+from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
+from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
 
 FOLDABLE_OPS = dict.fromkeys(lloperation.enum_foldable_ops())
 
@@ -184,7 +188,7 @@
         incoming[i].genvar = linkargs[i]
     return newblock
 
-def start_new_block(states_dic, jitstate, key):
+def start_new_block(states_dic, jitstate, key, global_resumer):
     memo = rvalue.freeze_memo()
     frozen = jitstate.freeze(memo)
     memo = rvalue.exactmatch_memo()
@@ -193,11 +197,17 @@
     assert res, "exactmatch() failed"
     newblock = enter_next_block(jitstate, outgoingvarboxes)
     states_dic[key] = frozen, newblock
+    if global_resumer:
+        greens_gv = jitstate.greens
+        rgenop = jitstate.curbuilder.rgenop
+        jitstate.promotion_path = PromotionPathRoot(greens_gv, rgenop,
+                                                    frozen, newblock,
+                                                    global_resumer)
 start_new_block._annspecialcase_ = "specialize:arglltype(2)"
 
-def retrieve_jitstate_for_merge(states_dic, jitstate, key):
+def retrieve_jitstate_for_merge(states_dic, jitstate, key, global_resumer):
     if key not in states_dic:
-        start_new_block(states_dic, jitstate, key)
+        start_new_block(states_dic, jitstate, key, global_resumer)
         return False   # continue
 
     frozen, oldblock = states_dic[key]
@@ -219,7 +229,7 @@
         box.forcevar(jitstate.curbuilder, replace_memo)
     if replace_memo.boxes:
         jitstate.replace(replace_memo)
-    start_new_block(states_dic, jitstate, key)
+    start_new_block(states_dic, jitstate, key, global_resumer)
     return False       # continue
 retrieve_jitstate_for_merge._annspecialcase_ = "specialize:arglltype(2)"
 
@@ -304,6 +314,132 @@
 ##def ll_gvar_from_constant(jitstate, ll_value):
 ##    return jitstate.curbuilder.rgenop.genconst(ll_value)
 
+
+
+class ResumingInfo(object):
+    def __init__(self, promotion_point, gv_value, path):
+        self.promotion_point = promotion_point
+        self.gv_value = gv_value
+        self.path = path
+
+class PromotionPoint(object):
+    def __init__(self, flexswitch, promotion_path):
+        assert promotion_path is not None
+        self.flexswitch = flexswitch
+        self.promotion_path = promotion_path
+
+class AbstractPromotionPath(object):
+    pass
+
+class PromotionPathRoot(AbstractPromotionPath):
+    def __init__(self, greens_gv, rgenop, frozen, portalblock, global_resumer):
+        self.greens_gv = greens_gv
+        self.rgenop = rgenop
+        self.frozen = frozen
+        self.portalblock = portalblock
+        self.global_resumer = global_resumer
+
+    def follow_path(self, path):
+        return self
+
+    def continue_compilation(self, resuminginfo):
+        incoming = []
+        memo = rvalue.unfreeze_memo()
+        jitstate = self.frozen.unfreeze(incoming, memo)
+        kinds = [box.kind for box in incoming]
+        builder, vars_gv = self.rgenop.replay(self.portalblock, kinds)
+        for i in range(len(incoming)):
+            incoming[i].genvar = vars_gv[i]
+        jitstate.curbuilder = builder
+        jitstate.greens = self.greens_gv
+        jitstate.resuming = resuminginfo
+        assert jitstate.frame.backframe is None
+        self.global_resumer(jitstate)
+
+class PromotionPathNode(AbstractPromotionPath):
+    def __init__(self, next):
+        self.next = next
+    def follow_path(self, path):
+        path.append(self.direct)
+        return self.next.follow_path(path)
+
+class PromotionPathDirect(PromotionPathNode):
+    direct = True
+
+class PromotionPathIndirect(PromotionPathNode):
+    direct = False
+
+def ll_continue_compilation(promotion_point_ptr, value):
+    try:
+        promotion_point = cast_base_ptr_to_instance(PromotionPoint,
+                                                    promotion_point_ptr)
+        path = []
+        root = promotion_point.promotion_path.follow_path(path)
+        gv_value = root.rgenop.genconst(value)
+        resuminginfo = ResumingInfo(promotion_point, gv_value, path)
+        root.continue_compilation(resuminginfo)
+    except Exception, e:
+        llop.debug_fatalerror(lltype.Void, "compilation-time error", e)
+
+class PromotionDesc:
+    __metatype__ = cachedtype
+
+    def __init__(self, ERASED, hrtyper):
+##        (s_PromotionPoint,
+##         r_PromotionPoint) = hrtyper.s_r_instanceof(PromotionPoint)
+        fnptr = hrtyper.annhelper.delayedfunction(
+            ll_continue_compilation,
+            [annmodel.SomePtr(base_ptr_lltype()),
+             annmodel.lltype_to_annotation(ERASED)],
+            annmodel.s_None, needtype=True)
+        RGenOp = hrtyper.RGenOp
+        self.gv_continue_compilation = RGenOp.constPrebuiltGlobal(fnptr)
+        self.sigtoken = RGenOp.sigToken(lltype.typeOf(fnptr).TO)
+##        self.PROMOTION_POINT = r_PromotionPoint.lowleveltype
+
+    def _freeze_(self):
+        return True
+
+def ll_promote(jitstate, box, promotiondesc):
+    if box.is_constant():
+        save_greens(jitstate, box.genvar)
+        return False
+    else:
+        incoming = []
+        memo = rvalue.enter_block_memo()
+        jitstate.enter_block(incoming, memo)
+        switchblock = enter_next_block(jitstate, incoming)
+
+        if jitstate.resuming is None:
+            builder = jitstate.curbuilder
+            flexswitch = builder.flexswitch(box.getgenvar(builder))
+            # default case of the switch:
+            enter_block(jitstate)
+            pm = PromotionPoint(flexswitch, jitstate.promotion_path)
+            ll_pm = cast_instance_to_base_ptr(pm)
+            gv_pm = builder.rgenop.genconst(ll_pm)
+            builder.genop_call(promotiondesc.sigtoken,
+                               promotiondesc.gv_continue_compilation,
+                               [gv_pm, box.getgenvar(builder)])
+            linkargs = []
+            for box in incoming:
+                linkargs.append(box.getgenvar(builder))
+            builder.finish_and_goto(linkargs, switchblock)
+            return True
+        else:
+            assert jitstate.promotion_path is None
+            resuming = jitstate.resuming
+            assert len(resuming.path) == 0
+            pm = resuming.promotion_point
+            newbuilder = pm.flexswitch.add_case(resuming.gv_value)
+
+            jitstate.resuming = None
+            jitstate.promotion_path = pm.promotion_path
+            jitstate.curbuilder = newbuilder
+            enter_block(jitstate)
+            save_greens(jitstate, resuming.gv_value)
+            return False
+
 # ____________________________________________________________
 
 class BaseDispatchQueue(object):
@@ -346,6 +482,18 @@
             assert vframe.backframe is None
         return fullmatch
 
+    def unfreeze(self, incomingvarboxes, memo):
+        local_boxes = []
+        for fzbox in self.fz_local_boxes:
+            local_boxes.append(fzbox.unfreeze(incomingvarboxes, memo))
+        if self.fz_backframe is not None:
+            backframe = self.fz_backframe.unfreeze(incomingvarboxes, memo)
+        else:
+            backframe = None
+        vframe = VirtualFrame(backframe, BaseDispatchQueue())
+        vframe.local_boxes = local_boxes
+        return vframe
+
 
 class FrozenJITState(object):
     #fz_frame = ...           set by freeze()
@@ -368,6 +516,12 @@
             fullmatch = False
         return fullmatch
 
+    def unfreeze(self, incomingvarboxes, memo):
+        frame         = self.fz_frame        .unfreeze(incomingvarboxes, memo)
+        exc_type_box  = self.fz_exc_type_box .unfreeze(incomingvarboxes, memo)
+        exc_value_box = self.fz_exc_value_box.unfreeze(incomingvarboxes, memo)
+        return JITState(None, frame, exc_type_box, exc_value_box)
+
 
 class VirtualFrame(object):
 
@@ -410,15 +564,17 @@
 class JITState(object):
     returnbox = None
     next      = None   # for linked lists
+    resuming  = None   # or a ResumingInfo
 
     def __init__(self, builder, frame, exc_type_box, exc_value_box,
-                 resumepoint=-1, newgreens=[]):
+                 resumepoint=-1, newgreens=[], promotion_path=None):
         self.curbuilder = builder
         self.frame = frame
         self.exc_type_box = exc_type_box
         self.exc_value_box = exc_value_box
         self.resumepoint = resumepoint
         self.greens = newgreens
+        self.promotion_path = promotion_path
 
     def split(self, newbuilder, newresumepoint, newgreens):
         memo = rvalue.copy_memo()
@@ -427,7 +583,9 @@
                                   self.exc_type_box .copy(memo),
                                   self.exc_value_box.copy(memo),
                                   newresumepoint,
-                                  newgreens)
+                                  newgreens,
+                                  PromotionPathIndirect(self.promotion_path))
+        self.promotion_path = PromotionPathDirect(self.promotion_path)
         # add the later_jitstate to the chain of pending-for-dispatch_next()
         dispatch_queue = self.frame.dispatch_queue
         later_jitstate.next = dispatch_queue.split_chain
@@ -456,6 +614,9 @@
 enter_graph._annspecialcase_ = 'specialize:arg(1)'
 # XXX is that too many specializations? ^^^
 
+class CompilationInterrupted(Exception):
+    pass
+
 def merge_returning_jitstates(jitstate):
     return_chain = jitstate.frame.dispatch_queue.return_chain
     return_cache = {}
@@ -463,17 +624,18 @@
     while return_chain is not None:
         jitstate = return_chain
         return_chain = return_chain.next
-        res = retrieve_jitstate_for_merge(return_cache, jitstate, ())
+        res = retrieve_jitstate_for_merge(return_cache, jitstate, (), None)
         if res is False:    # not finished
             jitstate.next = still_pending
             still_pending = jitstate
-    assert still_pending is not None
+    if still_pending is None:
+        raise CompilationInterrupted
     most_general_jitstate = still_pending
     still_pending = still_pending.next
     while still_pending is not None:
         jitstate = still_pending
         still_pending = still_pending.next
-        res = retrieve_jitstate_for_merge(return_cache, jitstate, ())
+        res = retrieve_jitstate_for_merge(return_cache, jitstate, (), None)
         assert res is True   # finished
     return most_general_jitstate
 

Modified: pypy/branch/jit-promotion/pypy/jit/timeshifter/rtyper.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtyper.py	(original)
+++ pypy/branch/jit-promotion/pypy/jit/timeshifter/rtyper.py	Wed Sep 27 21:21:50 2006
@@ -191,6 +191,14 @@
         # the graph is transformed already
         return self.annotator.bookkeeper.tsgraphsigs[tsgraph]
 
+    def get_residual_functype(self, tsgraph):
+        ha = self.annotator
+        args_hs, hs_res = self.get_sig_hs(ha.translator.graphs[0])
+        RESTYPE = originalconcretetype(hs_res)
+        ARGS = [originalconcretetype(hs_arg) for hs_arg in args_hs
+                                             if not hs_arg.is_green()]
+        return lltype.FuncType(ARGS, RESTYPE)
+
     def make_new_lloplist(self, block):
         return HintLowLevelOpList(self)
 
@@ -230,8 +238,11 @@
         try:
             return self.dispatchsubclasses[mergepointfamily]
         except KeyError:
-            attrnames = mergepointfamily.getattrnames()
-            subclass = rtimeshift.build_dispatch_subclass(attrnames)
+            if mergepointfamily.is_global:
+                subclass = rtimeshift.BaseDispatchQueue
+            else:
+                attrnames = mergepointfamily.getattrnames()
+                subclass = rtimeshift.build_dispatch_subclass(attrnames)
             self.dispatchsubclasses[mergepointfamily] = subclass
             return subclass
 
@@ -357,24 +368,6 @@
                                                [c_opdesc, v_jitstate]    + args_v,
                                                ts.s_RedBox)
 
-    def translate_op_hint(self, hop):
-        # don't try to generate hint operations, just discard them
-        hints = hop.args_v[-1].value
-        if hints.get('forget', False):
-            T = originalconcretetype(hop.args_s[0])
-            v_redbox = hop.inputarg(self.getredrepr(T), arg=0)
-            assert isinstance(hop.r_result, GreenRepr)
-            ts = self
-            c_T = hop.inputconst(lltype.Void, T)
-            s_T = ts.rtyper.annotator.bookkeeper.immutablevalue(T)
-            s_res = annmodel.lltype_to_annotation(T)
-            return hop.llops.genmixlevelhelpercall(rvalue.ll_getvalue,
-                                                   [ts.s_RedBox, s_T],
-                                                   [v_redbox,    c_T],
-                                                   s_res)
-                                                   
-        return hop.inputarg(hop.r_result, arg=0)
-
     def translate_op_debug_log_exc(self, hop): # don't timeshift debug_log_exc
         pass
 
@@ -738,17 +731,25 @@
                                         args_s, args_v,
                                         annmodel.s_None)
 
-    def translate_op_merge_point(self, hop):
+    def translate_op_merge_point(self, hop, global_resumer=None):
         mpfamily = hop.args_v[0].value
         attrname = hop.args_v[1].value
         DispatchQueueSubclass = self.get_dispatch_subclass(mpfamily)
 
-        def merge_point(jitstate, *key):
-            dispatch_queue = jitstate.frame.dispatch_queue
-            assert isinstance(dispatch_queue, DispatchQueueSubclass)
-            states_dic = getattr(dispatch_queue, attrname)
-            return rtimeshift.retrieve_jitstate_for_merge(states_dic,
-                                                          jitstate, key)
+        if mpfamily.is_global:
+            states_dic = {}
+            def merge_point(jitstate, *key):
+                return rtimeshift.retrieve_jitstate_for_merge(states_dic,
+                                                              jitstate, key,
+                                                              global_resumer)
+        else:
+            def merge_point(jitstate, *key):
+                dispatch_queue = jitstate.frame.dispatch_queue
+                assert isinstance(dispatch_queue, DispatchQueueSubclass)
+                states_dic = getattr(dispatch_queue, attrname)
+                return rtimeshift.retrieve_jitstate_for_merge(states_dic,
+                                                              jitstate, key,
+                                                              global_resumer)
 
         greens_v = []
         greens_s = []
@@ -767,6 +768,37 @@
                              [v_jitstate     ] + greens_v,
                              annmodel.SomeBool())
 
+    def translate_op_global_merge_point(self, hop):
+        mpfamily = hop.args_v[0].value
+        attrname = hop.args_v[1].value
+        N = mpfamily.resumepoint_after_mergepoint[attrname]
+        tsgraph = mpfamily.tsgraph
+        ts_fnptr = self.gettscallable(tsgraph)
+        TS_FUNC = lltype.typeOf(ts_fnptr)
+        dummy_args = [ARG._defl() for ARG in TS_FUNC.TO.ARGS[1:]]
+        dummy_args = tuple(dummy_args)
+        JITSTATE = self.r_JITState.lowleveltype
+        RESIDUAL_FUNCTYPE = self.get_residual_functype(tsgraph)
+        residualSigToken = self.RGenOp.sigToken(RESIDUAL_FUNCTYPE)
+        ll_finish_jitstate = self.ll_finish_jitstate
+
+        args_s = [self.s_JITState] + [annmodel.lltype_to_annotation(ARG)
+                                      for ARG in TS_FUNC.TO.ARGS[1:]]
+        s_res = self.s_JITState
+        tsfn = annlowlevel.PseudoHighLevelCallable(ts_fnptr, args_s, s_res)
+
+        def call_for_global_resuming(jitstate):
+            jitstate.resumepoint = N
+            try:
+                finaljitstate = tsfn(jitstate, *dummy_args)
+            except rtimeshift.CompilationInterrupted:
+                pass
+            else:
+                ll_finish_jitstate(finaljitstate, residualSigToken)
+
+        return self.translate_op_merge_point(hop,
+                        global_resumer = call_for_global_resuming)
+
     def translate_op_save_return(self, hop):
         v_jitstate = hop.llops.getjitstate()
         return hop.llops.genmixlevelhelpercall(rtimeshift.save_return,
@@ -781,11 +813,29 @@
                                                   [v_jitstate     ],
                                                   self.s_JITState)
         hop.llops.setjitstate(v_newjs)
+
+    def translate_op_getresumepoint(self, hop):
+        v_jitstate = hop.llops.getjitstate()
         return hop.llops.genmixlevelhelpercall(rtimeshift.getresumepoint,
                                                [self.s_JITState],
-                                               [v_newjs        ],
+                                               [v_jitstate     ],
                                                annmodel.SomeInteger())
 
+    def translate_op_promote(self, hop):
+        TYPE = originalconcretetype(hop.args_s[0])
+        r_arg = self.getredrepr(TYPE)
+        [v_box] = hop.inputargs(r_arg)
+        r_result = self.getgreenrepr(TYPE)
+        ERASED = annmodel.annotation_to_lltype(r_result.erased_annotation())
+        desc = rtimeshift.PromotionDesc(ERASED, self)
+        s_desc = self.rtyper.annotator.bookkeeper.immutablevalue(desc)
+        c_desc = hop.inputconst(lltype.Void, desc)
+        v_jitstate = hop.llops.getjitstate()
+        return hop.llops.genmixlevelhelpercall(rtimeshift.ll_promote,
+                                    [self.s_JITState, self.s_RedBox, s_desc],
+                                    [v_jitstate     , v_box        , c_desc],
+                                    annmodel.SomeBool())
+
     # handling of the various kinds of calls
 
     def translate_op_oopspec_call(self, hop):

Modified: pypy/branch/jit-promotion/pypy/jit/timeshifter/rvalue.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rvalue.py	(original)
+++ pypy/branch/jit-promotion/pypy/jit/timeshifter/rvalue.py	Wed Sep 27 21:21:50 2006
@@ -19,6 +19,9 @@
 def copy_memo():
     return Memo()
 
+def unfreeze_memo():
+    return Memo()
+
 
 class RedBox(object):
     __slots__ = ['kind', 'genvar']
@@ -135,9 +138,9 @@
             return memo[self]
         except KeyError:
             if self.is_constant():
-                result = FrozenIntConst(self.genvar)
+                result = FrozenIntConst(self.kind, self.genvar)
             else:
-                result = FrozenIntVar()
+                result = FrozenIntVar(self.kind)
             memo[self] = result
             return result
 
@@ -159,9 +162,9 @@
             return memo[self]
         except KeyError:
             if self.is_constant():
-                result = FrozenDoubleConst(self.genvar)
+                result = FrozenDoubleConst(self.kind, self.genvar)
             else:
-                result = FrozenDoubleVar()
+                result = FrozenDoubleVar(self.kind)
             memo[self] = result
             return result
 
@@ -205,14 +208,14 @@
             return boxmemo[self]
         except KeyError:
             if self.content:
-                result = FrozenPtrVirtual()
+                result = FrozenPtrVirtual(self.kind)
                 boxmemo[self] = result
                 result.fz_content = self.content.freeze(memo)
             else:
                 if self.is_constant():
-                    result = FrozenPtrConst(self.genvar)
+                    result = FrozenPtrConst(self.kind, self.genvar)
                 else:
-                    result = FrozenPtrVar()
+                    result = FrozenPtrVar(self.kind)
                 boxmemo[self] = result
             return result
 
@@ -234,11 +237,14 @@
 class FrozenValue(object):
     """An abstract value frozen in a saved state.
     """
+    def __init__(self, kind):
+        self.kind = kind
 
 
 class FrozenIntConst(FrozenValue):
 
-    def __init__(self, gv_const):
+    def __init__(self, kind, gv_const):
+        self.kind = kind
         self.gv_const = gv_const
 
     def exactmatch(self, box, outgoingvarboxes, memo):
@@ -250,6 +256,10 @@
             outgoingvarboxes.append(box)
             return False
 
+    def unfreeze(self, incomingvarboxes, memo):
+        # XXX could return directly the original IntRedBox
+        return IntRedBox(self.kind, self.gv_const)
+
 
 class FrozenIntVar(FrozenValue):
 
@@ -265,10 +275,21 @@
             outgoingvarboxes.append(box)
             return False
 
+    def unfreeze(self, incomingvarboxes, memo):
+        memo = memo.boxes
+        if self not in memo:
+            newbox = IntRedBox(self.kind, None)
+            incomingvarboxes.append(newbox)
+            memo[self] = newbox
+            return newbox
+        else:
+            return memo[self]
+
 
 class FrozenDoubleConst(FrozenValue):
 
-    def __init__(self, gv_const):
+    def __init__(self, kind, gv_const):
+        self.kind = kind
         self.gv_const = gv_const
 
     def exactmatch(self, box, outgoingvarboxes, memo):
@@ -280,6 +301,9 @@
             outgoingvarboxes.append(box)
             return False
 
+    def unfreeze(self, incomingvarboxes, memo):
+        return DoubleRedBox(self.kind, self.gv_const)
+
 
 class FrozenDoubleVar(FrozenValue):
 
@@ -295,10 +319,21 @@
             outgoingvarboxes.append(box)
             return False
 
+    def unfreeze(self, incomingvarboxes, memo):
+        memo = memo.boxes
+        if self not in memo:
+            newbox = DoubleRedBox(self.kind, None)
+            incomingvarboxes.append(newbox)
+            memo[self] = newbox
+            return newbox
+        else:
+            return memo[self]
+
 
 class FrozenPtrConst(FrozenValue):
 
-    def __init__(self, gv_const):
+    def __init__(self, kind, gv_const):
+        self.kind = kind
         self.gv_const = gv_const
 
     def exactmatch(self, box, outgoingvarboxes, memo):
@@ -310,6 +345,9 @@
             outgoingvarboxes.append(box)
             return False
 
+    def unfreeze(self, incomingvarboxes, memo):
+        return PtrRedBox(self.kind, self.gv_const)
+
 
 class FrozenPtrVar(FrozenValue):
 
@@ -325,6 +363,16 @@
             outgoingvarboxes.append(box)
             return False
 
+    def unfreeze(self, incomingvarboxes, memo):
+        memo = memo.boxes
+        if self not in memo:
+            newbox = PtrRedBox(self.kind, None)
+            incomingvarboxes.append(newbox)
+            memo[self] = newbox
+            return newbox
+        else:
+            return memo[self]
+
 
 class FrozenPtrVirtual(FrozenValue):
 
@@ -336,3 +384,7 @@
         else:
             return self.fz_content.exactmatch(box.content, outgoingvarboxes,
                                               memo)
+
+    def unfreeze(self, incomingvarboxes, memo):
+        #return self.fz_content.unfreeze(self.kind, incomingvarboxes, memo)
+        raise NotImplementedError

Added: pypy/branch/jit-promotion/pypy/jit/timeshifter/test/test_promotion.py
==============================================================================
--- (empty file)
+++ pypy/branch/jit-promotion/pypy/jit/timeshifter/test/test_promotion.py	Wed Sep 27 21:21:50 2006
@@ -0,0 +1,26 @@
+import py
+from pypy.rpython.lltypesystem import lltype
+from pypy.jit.timeshifter.test.test_timeshift import TimeshiftingTests
+from pypy.rpython.objectmodel import hint
+
+
+class TestPromotion(TimeshiftingTests):
+
+    def test_simple_promotion(self):
+        def ll_two(k):
+            return (k+1)*2
+        def ll_function(n):
+            k = hint(n, promote=True)
+            k = ll_two(k)
+            return hint(k, variable=True)
+        ll_function._global_merge_points_ = True
+
+        # easy case: no promotion needed
+        res = self.timeshift(ll_function, [20], [0])
+        assert res == 42
+        self.check_insns({})
+
+        # the real test: with promotion
+        res = self.timeshift(ll_function, [20], [])
+        assert res == 42
+        self.check_insns(int_add=0, int_mul=0)

Modified: pypy/branch/jit-promotion/pypy/jit/timeshifter/test/test_timeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py	(original)
+++ pypy/branch/jit-promotion/pypy/jit/timeshifter/test/test_timeshift.py	Wed Sep 27 21:21:50 2006
@@ -99,8 +99,6 @@
 
         fresh_jitstate = hrtyper.ll_fresh_jitstate
         finish_jitstate = hrtyper.ll_finish_jitstate
-        args_hs, hs_res = hrtyper.get_sig_hs(ha.translator.graphs[0])
-        RESTYPE = originalconcretetype(hs_res)
         t = rtyper.annotator.translator
         for graph in ha.translator.graphs:
             checkgraph(graph)
@@ -119,11 +117,10 @@
         assert len(graph1.getargs()) == 1 + len(values)
         graph1varargs = graph1.getargs()[1:]
         timeshifted_entrypoint_args_s = []
-        residual_argtypes = []
         argcolors = []
         generate_code_args_s = []
 
-        for v, hs_arg, llvalue in zip(graph1varargs, args_hs, values):
+        for v, llvalue in zip(graph1varargs, values):
             s_var = annmodel.ll_to_annotation(llvalue)
             r = hrtyper.bindingrepr(v)
             residual_v = r.residual_values(llvalue)
@@ -133,8 +130,6 @@
             else:
                 color = "red"
                 assert residual_v == [llvalue], "XXX for now"
-                ARGTYPE = originalconcretetype(hs_arg)
-                residual_argtypes.append(ARGTYPE)
                 timeshifted_entrypoint_args_s.append(hrtyper.s_RedBox)
                 generate_code_args_s.append(annmodel.SomeBool())
             argcolors.append(color)
@@ -147,7 +142,7 @@
             [hrtyper.s_JITState]
             + timeshifted_entrypoint_args_s,
             hrtyper.s_JITState)
-        FUNC = lltype.FuncType(residual_argtypes, RESTYPE)
+        FUNC = hrtyper.get_residual_functype(ha.translator.graphs[0])
         argcolors = unrolling_iterable(argcolors)
         self.argcolors = argcolors
 
@@ -180,9 +175,13 @@
                     timeshifted_entrypoint_args += (box,)
 
             top_jitstate = fresh_jitstate(builder)
-            top_jitstate = timeshifted_entrypoint(top_jitstate,
+            try:
+                top_jitstate = timeshifted_entrypoint(top_jitstate,
                                                   *timeshifted_entrypoint_args)
-            finish_jitstate(top_jitstate, sigtoken)
+            except rtimeshift.CompilationInterrupted:
+                pass
+            else:
+                finish_jitstate(top_jitstate, sigtoken)
 
             gv_generated = rgenop.gencallableconst(sigtoken, "generated",
                                                    entrypoint)

Modified: pypy/branch/jit-promotion/pypy/jit/timeshifter/transform.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/transform.py	(original)
+++ pypy/branch/jit-promotion/pypy/jit/timeshifter/transform.py	Wed Sep 27 21:21:50 2006
@@ -13,8 +13,11 @@
 
 
 class MergePointFamily(object):
-    def __init__(self):
+    def __init__(self, tsgraph, is_global=False):
+        self.tsgraph = tsgraph
+        self.is_global = is_global
         self.count = 0
+        self.resumepoint_after_mergepoint = {}
     def add(self):
         result = self.count
         self.count += 1
@@ -30,27 +33,32 @@
         self.hannotator = hannotator
         self.graph = graph
         self.graphcolor = self.graph_calling_color(graph)
+        self.global_merge_points = self.graph_global_mps(self.graph)
         self.resumepoints = {}
-        self.mergepointfamily = MergePointFamily()
+        self.mergepoint_set = {}    # set of blocks
+        self.mergepointfamily = MergePointFamily(graph,
+                                                 self.global_merge_points)
         self.c_mpfamily = inputconst(lltype.Void, self.mergepointfamily)
         self.tsgraphs_seen = []
 
     def transform(self):
-        mergepoints = list(self.enumerate_merge_points())
+        self.compute_merge_points()
         self.insert_save_return()
         self.insert_splits()
-        for block in mergepoints:
-            self.insert_merge(block)
         self.split_after_calls()
-        self.insert_dispatcher()
+        self.handle_hints()
+        self.insert_merge_points()
         self.insert_enter_graph()
+        self.insert_dispatcher()
         self.insert_leave_graph()
 
-    def enumerate_merge_points(self):
+    def compute_merge_points(self):
         entrymap = mkentrymap(self.graph)
         for block, links in entrymap.items():
             if len(links) > 1 and block is not self.graph.returnblock:
-                yield block
+                self.mergepoint_set[block] = True
+        if self.global_merge_points:
+            self.mergepoint_set[self.graph.startblock] = True
 
     def graph_calling_color(self, tsgraph):
         args_hs, hs_res = self.hannotator.bookkeeper.tsgraphsigs[tsgraph]
@@ -61,6 +69,12 @@
         else:
             return 'red'
 
+    def graph_global_mps(self, tsgraph):
+        try:
+            return tsgraph.func._global_merge_points_
+        except AttributeError:
+            return False
+
     def timeshifted_graph_of(self, graph, args_v):
         bk = self.hannotator.bookkeeper
         args_hs = [self.hannotator.binding(v) for v in args_v]
@@ -147,6 +161,13 @@
                 reds.append(v)
         return reds, greens
 
+    def before_start_block(self):
+        entryblock = self.new_block_before(self.graph.startblock)
+        entryblock.isstartblock = True
+        self.graph.startblock.isstartblock = False
+        self.graph.startblock = entryblock
+        return entryblock
+
     def before_return_block(self):
         block = self.graph.returnblock
         block.operations = []
@@ -239,6 +260,21 @@
     def get_resume_point(self, block):
         return self.get_resume_point_link(block).exitcase
 
+    def go_to_if(self, block, target, v_finished_flag):
+        block.exitswitch = v_finished_flag
+        [link_f] = block.exits
+        link_t = Link([self.c_dummy], target)
+        link_f.exitcase = False
+        link_t.exitcase = True
+        block.recloseblock(link_f, link_t)
+
+    def go_to_dispatcher_if(self, block, v_finished_flag):
+        self.go_to_if(block, self.graph.returnblock, v_finished_flag)
+
+    def insert_merge_points(self):
+        for block in self.mergepoint_set:
+            self.insert_merge(block)
+
     def insert_merge(self, block):
         reds, greens = self.sort_by_color(block.inputargs)
         nextblock = self.naive_split_block(block, 0)
@@ -246,15 +282,15 @@
         self.genop(block, 'save_locals', reds)
         mp   = self.mergepointfamily.add()
         c_mp = inputconst(lltype.Void, mp)
-        v_finished_flag = self.genop(block, 'merge_point',
+        if self.global_merge_points:
+            self.genop(block, 'save_greens', greens)
+            prefix = 'global_'
+        else:
+            prefix = ''
+        v_finished_flag = self.genop(block, '%smerge_point' % (prefix,),
                                      [self.c_mpfamily, c_mp] + greens,
                                      resulttype = lltype.Bool)
-        block.exitswitch = v_finished_flag
-        [link_f] = block.exits
-        link_t = Link([self.c_dummy], self.graph.returnblock)
-        link_f.exitcase = False
-        link_t.exitcase = True
-        block.recloseblock(link_f, link_t)
+        self.go_to_dispatcher_if(block, v_finished_flag)
 
         restoreops = []
         mapping = {}
@@ -269,10 +305,26 @@
         SSA_to_SSI({block    : True,    # reachable from outside
                     nextblock: False}, self.hannotator)
 
+        if self.global_merge_points:
+            N = self.get_resume_point(nextblock)
+            self.mergepointfamily.resumepoint_after_mergepoint[mp] = N
+
     def insert_dispatcher(self):
-        if self.resumepoints:
+        if self.global_merge_points or self.resumepoints:
             block = self.before_return_block()
-            v_switchcase = self.genop(block, 'dispatch_next', [],
+            self.genop(block, 'dispatch_next', [])
+            if self.global_merge_points:
+                block = self.before_return_block()
+                entryblock = self.before_start_block()
+                v_rp = self.genop(entryblock, 'getresumepoint', [],
+                                  resulttype = lltype.Signed)
+                c_zero = inputconst(lltype.Signed, 0)
+                v_abnormal_entry = self.genop(entryblock, 'int_ge',
+                                              [v_rp, c_zero],
+                                              resulttype = lltype.Bool)
+                self.go_to_if(entryblock, block, v_abnormal_entry)
+
+            v_switchcase = self.genop(block, 'getresumepoint', [],
                                       resulttype = lltype.Signed)
             block.exitswitch = v_switchcase
             defaultlink = block.exits[0]
@@ -297,11 +349,7 @@
         self.genop(block, 'save_return', [])
 
     def insert_enter_graph(self):
-        entryblock = self.new_block_before(self.graph.startblock)
-        entryblock.isstartblock = True
-        self.graph.startblock.isstartblock = False
-        self.graph.startblock = entryblock
-
+        entryblock = self.before_start_block()
         self.genop(entryblock, 'enter_graph', [self.c_mpfamily])
 
     def insert_leave_graph(self):
@@ -363,6 +411,11 @@
     def make_call(self, block, op, save_locals_vars, color='red'):
         self.genop(block, 'save_locals', save_locals_vars)
         targets = dict(self.graphs_from(op))
+        for tsgraph in targets.values():
+            if self.graph_global_mps(tsgraph):
+                # make sure jitstate.resumepoint is set to zero
+                self.genop(block, 'resetresumepoint', [])
+                break
         if len(targets) == 1:
             [tsgraph] = targets.values()
             c_tsgraph = inputconst(lltype.Void, tsgraph)
@@ -475,5 +528,56 @@
         link.args = []
         link.target = self.get_resume_point_link(nextblock).target
 
-        self.insert_merge(nextblock)  # to merge some of the possibly many
-                                      # return jitstates
+        self.mergepoint_set[nextblock] = True  # to merge some of the possibly
+                                               # many return jitstates
+
+    # __________ hints __________
+
+    def handle_hints(self):
+        for block in list(self.graph.iterblocks()):
+            for i in range(len(block.operations)-1, -1, -1):
+                op = block.operations[i]
+                if op.opname == 'hint':
+                    hints = op.args[1].value
+                    for key, value in hints.items():
+                        if value == True:
+                            methname = 'handle_%s_hint' % (key,)
+                            if hasattr(self, methname):
+                                handler = getattr(self, methname)
+                                break
+                    else:
+                        handler = self.handle_default_hint
+                    handler(block, i)
+
+    def handle_default_hint(self, block, i):
+        # just discard the hint by default
+        op = block.operations[i]
+        newop = SpaceOperation('same_as', [op.args[0]], op.result)
+        block.operations[i] = newop
+
+    def handle_forget_hint(self, block, i):
+        # a hint for testing only
+        op = block.operations[i]
+        assert self.binding(op.result).is_green()
+        assert not self.binding(op.args[0]).is_green()
+        newop = SpaceOperation('revealconst', [op.args[0]], op.result)
+        block.operations[i] = newop
+
+    def handle_promote_hint(self, block, i):
+        op = block.operations[i]
+        c_zero = inputconst(lltype.Signed, 0)
+        newop = SpaceOperation('restore_green', [c_zero], op.result)
+        block.operations[i] = newop
+
+        link = support.split_block_with_keepalive(block, i,
+                                                  annotator=self.hannotator)
+        nextblock = link.target
+
+        reds, greens = self.sort_by_color(link.args)
+        v_promote = op.args[0]
+        if v_promote not in reds:
+            reds.append(v_promote)
+        self.genop(block, 'save_locals', reds)
+        v_finished_flag = self.genop(block, 'promote', [v_promote],
+                                     resulttype = lltype.Bool)
+        self.go_to_dispatcher_if(block, v_finished_flag)

Modified: pypy/branch/jit-promotion/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/branch/jit-promotion/pypy/rpython/lltypesystem/lloperation.py	Wed Sep 27 21:21:50 2006
@@ -402,6 +402,7 @@
     'debug_pdb':            LLOp(),
     'debug_log_exc':        LLOp(),
     'debug_assert':         LLOp(canfold=True),
+    'debug_fatalerror':     LLOp(),
 }
 
     # __________ operations on PyObjects __________



More information about the Pypy-commit mailing list