[pypy-svn] r32715 - in pypy/dist/pypy: annotation jit/codegen jit/codegen/i386 jit/codegen/llgraph jit/codegen/llgraph/test jit/hintannotator jit/timeshifter jit/timeshifter/test rpython rpython/lltypesystem tool

arigo at codespeak.net arigo at codespeak.net
Thu Sep 28 20:10:24 CEST 2006


Author: arigo
Date: Thu Sep 28 20:10:20 2006
New Revision: 32715

Added:
   pypy/dist/pypy/jit/codegen/llgraph/test/test_rgenop.py
      - copied unchanged from r32711, pypy/branch/jit-promotion/pypy/jit/codegen/llgraph/test/test_rgenop.py
   pypy/dist/pypy/jit/timeshifter/test/test_promotion.py
      - copied unchanged from r32711, pypy/branch/jit-promotion/pypy/jit/timeshifter/test/test_promotion.py
Removed:
   pypy/dist/pypy/jit/codegen/llgraph/test/test_llimpl.py
Modified:
   pypy/dist/pypy/annotation/annrpython.py
   pypy/dist/pypy/jit/codegen/i386/ri386genop.py
   pypy/dist/pypy/jit/codegen/llgraph/llimpl.py
   pypy/dist/pypy/jit/codegen/llgraph/rgenop.py
   pypy/dist/pypy/jit/codegen/model.py
   pypy/dist/pypy/jit/hintannotator/model.py
   pypy/dist/pypy/jit/timeshifter/rcontainer.py
   pypy/dist/pypy/jit/timeshifter/rtimeshift.py
   pypy/dist/pypy/jit/timeshifter/rtyper.py
   pypy/dist/pypy/jit/timeshifter/rvalue.py
   pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py
   pypy/dist/pypy/jit/timeshifter/transform.py
   pypy/dist/pypy/rpython/annlowlevel.py
   pypy/dist/pypy/rpython/llinterp.py
   pypy/dist/pypy/rpython/lltypesystem/lloperation.py
   pypy/dist/pypy/tool/sourcetools.py
Log:
(pedronis, arre, arigo)

Merge the jit-promotion branch:

   svn merge http://codespeak.net/svn/pypy/dist@32682 
              http://codespeak.net/svn/pypy/branch/jit-promotion

It adds "promotion": with  x = hint(x, promote=True)  we can force a red
variable to become green.  This is implemented by pausing the
compilation and resuming it only when we get a run-time value arriving.
The "pause" contains run-time code that is a "flexible switch": a switch
where new cases can be added dynamically.  The default case is the one
that calls back the compiler.



Modified: pypy/dist/pypy/annotation/annrpython.py
==============================================================================
--- pypy/dist/pypy/annotation/annrpython.py	(original)
+++ pypy/dist/pypy/annotation/annrpython.py	Thu Sep 28 20:10:20 2006
@@ -722,7 +722,8 @@
         try:
             resultcell = consider_meth(*argcells)
         except Exception:
-            raise_nicer_exception(op)
+            graph = self.bookkeeper.position_key[0]
+            raise_nicer_exception(op, str(graph))
         if resultcell is None:
             resultcell = annmodel.s_ImpossibleValue  # no return value
         elif resultcell == annmodel.s_ImpossibleValue:

Modified: pypy/dist/pypy/jit/codegen/i386/ri386genop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/ri386genop.py	(original)
+++ pypy/dist/pypy/jit/codegen/i386/ri386genop.py	Thu Sep 28 20:10:20 2006
@@ -436,8 +436,6 @@
         return self.returnvar(eax)
 
     op_uint_is_true = op_int_is_true
-    op_uint_neg     = op_int_neg
-    op_uint_abs     = identity
     op_uint_invert  = op_int_invert
     op_uint_add     = op_int_add
     op_uint_sub     = op_int_sub

Modified: pypy/dist/pypy/jit/codegen/llgraph/llimpl.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/llgraph/llimpl.py	(original)
+++ pypy/dist/pypy/jit/codegen/llgraph/llimpl.py	Thu Sep 28 20:10:20 2006
@@ -23,16 +23,41 @@
     c = from_opaque_object(gv_type)
     return isinstance(c.value, lltype.Ptr)
 
-def initblock(opaqueptr):
-    init_opaque_object(opaqueptr, flowmodel.Block([]))
-
 def newblock():
-    blockcontainer = lltype.malloc(BLOCKCONTAINERTYPE)
-    initblock(blockcontainer.obj)
-    return blockcontainer
+    block = flowmodel.Block([])
+    return to_opaque_object(block)
+
+def newgraph(gv_FUNCTYPE):
+    FUNCTYPE = from_opaque_object(gv_FUNCTYPE).value
+    inputargs = []
+    erasedinputargs = []
+    for ARG in FUNCTYPE.ARGS:
+        v = flowmodel.Variable()
+        v.concretetype = ARG
+        inputargs.append(v)
+        v = flowmodel.Variable()
+        v.concretetype = lltype.erasedType(ARG)
+        erasedinputargs.append(v)
+    startblock = flowmodel.Block(inputargs)
+    return_var = flowmodel.Variable()
+    return_var.concretetype = FUNCTYPE.RESULT
+    graph = flowmodel.FunctionGraph("in_progress", startblock, return_var)
+    v1 = flowmodel.Variable()
+    v1.concretetype = lltype.erasedType(FUNCTYPE.RESULT)
+    graph.prereturnblock = flowmodel.Block([v1])
+    casting_link(graph.prereturnblock, [v1], graph.returnblock)
+    substartblock = flowmodel.Block(erasedinputargs)
+    casting_link(graph.startblock, inputargs, substartblock)
+    return to_opaque_object(graph)
+
+def getstartblock(graph):
+    graph = from_opaque_object(graph)
+    [link] = graph.startblock.exits
+    substartblock = link.target
+    return to_opaque_object(substartblock)
 
-def geninputarg(blockcontainer, gv_CONCRETE_TYPE):
-    block = from_opaque_object(blockcontainer.obj)
+def geninputarg(block, gv_CONCRETE_TYPE):
+    block = from_opaque_object(block)
     assert not block.operations, "block already contains operations"
     assert block.exits == [], "block already closed"
     CONCRETE_TYPE = from_opaque_object(gv_CONCRETE_TYPE).value
@@ -41,6 +66,11 @@
     block.inputargs.append(v)
     return to_opaque_object(v)
 
+def getinputarg(block, i):
+    block = from_opaque_object(block)
+    v = block.inputargs[i]
+    return to_opaque_object(v)
+
 def _inputvars(vars):
     newvars = []
     if not isinstance(vars, list):
@@ -67,12 +97,12 @@
         res.append(v)
     return res
 
-def cast(blockcontainer, gv_TYPE, gv_var):
+def cast(block, gv_TYPE, gv_var):
     TYPE = from_opaque_object(gv_TYPE).value
     v = from_opaque_object(gv_var)
     if TYPE != v.concretetype:
         assert v.concretetype == lltype.erasedType(TYPE)
-        block = from_opaque_object(blockcontainer.obj)
+        block = from_opaque_object(block)
         v2 = flowmodel.Variable()
         v2.concretetype = TYPE
         op = flowmodel.SpaceOperation('cast_pointer', [v], v2)
@@ -90,12 +120,12 @@
         return v2
     return v
 
-def genop(blockcontainer, opname, vars_gv, gv_RESULT_TYPE):
+def genop(block, opname, vars_gv, gv_RESULT_TYPE):
     # 'opname' is a constant string
     # gv_RESULT_TYPE comes from constTYPE
     if not isinstance(opname, str):
         opname = LLSupport.from_rstr(opname)
-    block = from_opaque_object(blockcontainer.obj)
+    block = from_opaque_object(block)
     assert block.exits == [], "block already closed"
     opvars = _inputvars(vars_gv)
     if gv_RESULT_TYPE is guess:
@@ -125,14 +155,15 @@
     result = op.fold(*examples)
     return lltype.typeOf(result)
 
-def gencallableconst(name, targetcontainer, gv_FUNCTYPE):
+def gencallableconst(name, graph, 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)
+    graph = from_opaque_object(graph)
+    graph.name = name
     FUNCTYPE = from_opaque_object(gv_FUNCTYPE).value
     fptr = lltype.functionptr(FUNCTYPE, name,
-                              graph=_buildgraph(target, FUNCTYPE))
+                              graph=_buildgraph(graph, FUNCTYPE))
     return genconst(fptr)
 
 def genconst(llvalue):
@@ -181,14 +212,14 @@
     c.concretetype = lltype.Void
     return to_opaque_object(c)
 
-def closeblock1(blockcontainer):
-    block = from_opaque_object(blockcontainer.obj)
+def closeblock1(block):
+    block = from_opaque_object(block)
     link = flowmodel.Link([], None)
     block.closeblock(link)
     return to_opaque_object(link)
 
-def closeblock2(blockcontainer, exitswitch):
-    block = from_opaque_object(blockcontainer.obj)
+def closeblock2(block, exitswitch):
+    block = from_opaque_object(block)
     exitswitch = from_opaque_object(exitswitch)
     assert isinstance(exitswitch, flowmodel.Variable)
     block.exitswitch = exitswitch
@@ -202,6 +233,29 @@
     return pseudotuple(to_opaque_object(false_link),
                        to_opaque_object(true_link))
 
+def closeblockswitch(block, exitswitch):
+    block = from_opaque_object(block)
+    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(block, exitcase):
+    block = from_opaque_object(block)
+    exitcase = from_opaque_object(exitcase)
+    assert isinstance(exitcase, flowmodel.Constant)
+    assert isinstance(block.exitswitch, flowmodel.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):
@@ -233,84 +287,55 @@
     else:
         raise TypeError
 
-def closelink(link, vars, targetblockcontainer):
-    link = from_opaque_object(link)
-    targetblock = from_opaque_object(targetblockcontainer.obj)
-    vars = _inputvars(vars)
-    _closelink(link, vars, targetblock)
+def closelink(link, vars, targetblock):
+    try:
+        link = from_opaque_object(link)
+        targetblock = from_opaque_object(targetblock)
+        vars = _inputvars(vars)
+        _closelink(link, vars, targetblock)
+    except Exception, e:
+        import sys; tb = sys.exc_info()[2]
+        import pdb; pdb.post_mortem(tb)
+        raise
 
-def closereturnlink(link, returnvar):
+def closereturnlink(link, returnvar, graph):
     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
+    graph = from_opaque_object(graph)
+    _closelink(link, [returnvar], graph.prereturnblock)
+
+def casting_link(source, sourcevars, target):
+    assert len(sourcevars) == len(target.inputargs)
+    linkargs = []
+    for v, target_v in zip(sourcevars, target.inputargs):
+        if v.concretetype == target_v.concretetype:
+            linkargs.append(v)
+        else:
+            erasedv = flowmodel.Variable()
+            erasedv.concretetype = target_v.concretetype
+            source.operations.append(flowmodel.SpaceOperation('cast_pointer',
+                                                              [v],
+                                                              erasedv))
+            linkargs.append(erasedv)
+    source.closeblock(flowmodel.Link(linkargs, target))
+
+# ____________________________________________________________
 
 class PseudoRTyper(object):
     def __init__(self):
         from pypy.rpython.typesystem import LowLevelTypeSystem
         self.type_system = LowLevelTypeSystem.instance
 
-def casting_bridge(FROMS, TOS, target):
-    if FROMS != TOS:
-        operations = []
-        inputargs = []
-        linkargs = []
-        for FROM, TO  in zip(FROMS, TOS):
-            v = flowmodel.Variable()
-            v.concretetype = FROM
-            inputargs.append(v)
-            if FROM == TO:
-                linkargs.append(v)
-            else:
-                erasedv = flowmodel.Variable()
-                erasedv.concretetype = TO
-                operations.append(flowmodel.SpaceOperation('cast_pointer',
-                                                           [v],
-                                                           erasedv))
-                linkargs.append(erasedv)
-        bridgeblock = flowmodel.Block(inputargs)
-        bridgeblock.operations = operations
-        bridge = flowmodel.Link(linkargs, target)
-        bridgeblock.closeblock(bridge)
-        return bridgeblock
-    else:
-        return target
-        
-def _buildgraph(block, 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)
+def _buildgraph(graph, FUNCTYPE):
     flowmodel.checkgraph(graph)
     eliminate_empty_blocks(graph)
     join_blocks(graph)
     graph.rgenop = True
     return graph
 
-def buildgraph(blockcontainer, FUNCTYPE):
-    block = from_opaque_object(blockcontainer.obj)
-    return _buildgraph(block, FUNCTYPE)
+def buildgraph(graph, FUNCTYPE):
+    graph = from_opaque_object(graph)
+    return _buildgraph(graph, FUNCTYPE)
 
 def testgengraph(gengraph, args, viewbefore=False, executor=LLInterpreter):
     if viewbefore:
@@ -318,32 +343,40 @@
     llinterp = executor(PseudoRTyper())
     return llinterp.eval_graph(gengraph, args)
     
-def runblock(blockcontainer, FUNCTYPE, args,
+def runblock(graph, FUNCTYPE, args,
              viewbefore=False, executor=LLInterpreter):
-    graph = buildgraph(blockcontainer, FUNCTYPE)
+    graph = buildgraph(graph, FUNCTYPE)
     return testgengraph(graph, args, viewbefore, executor)
 
+def show_incremental_progress(graph):
+    from pypy import conftest
+    if conftest.option.view:
+        graph = from_opaque_object(graph)
+        graph.show()
+
 # ____________________________________________________________
 # RTyping of the above functions
 
-from pypy.rpython.extfunctable import declaretype, declareptrtype, declare
+from pypy.rpython.extfunctable import declareptrtype
 
-blocktypeinfo = declaretype(flowmodel.Block, "Block")
+blocktypeinfo = declareptrtype(flowmodel.Block, "Block")
 consttypeinfo = declareptrtype(flowmodel.Constant, "ConstOrVar")
 vartypeinfo   = declareptrtype(flowmodel.Variable, "ConstOrVar")
 vartypeinfo.set_lltype(consttypeinfo.get_lltype())   # force same lltype
 linktypeinfo  = declareptrtype(flowmodel.Link, "Link")
+graphtypeinfo = declareptrtype(flowmodel.FunctionGraph, "FunctionGraph")
 
 CONSTORVAR = lltype.Ptr(consttypeinfo.get_lltype())
-BLOCKCONTAINERTYPE = blocktypeinfo.get_lltype()
-BLOCK = lltype.Ptr(BLOCKCONTAINERTYPE)
+BLOCK = lltype.Ptr(blocktypeinfo.get_lltype())
 LINK = lltype.Ptr(linktypeinfo.get_lltype())
+GRAPH = lltype.Ptr(graphtypeinfo.get_lltype())
 
 # support constants and types
 
 nullvar = lltype.nullptr(CONSTORVAR.TO)
 nullblock = lltype.nullptr(BLOCK.TO)
 nulllink = lltype.nullptr(LINK.TO)
+nullgraph = lltype.nullptr(GRAPH.TO)
 gv_Void = constTYPE(lltype.Void)
 
 dummy_placeholder = placeholder(None)
@@ -384,9 +417,14 @@
 s_ConstOrVar = annmodel.SomePtr(CONSTORVAR)#annmodel.SomeExternalObject(flowmodel.Variable)
 s_Link = annmodel.SomePtr(LINK)#annmodel.SomeExternalObject(flowmodel.Link)
 s_LinkPair = annmodel.SomeTuple([s_Link, s_Link])
+s_Block = annmodel.SomePtr(BLOCK)
+s_Graph = annmodel.SomePtr(GRAPH)
 
-setannotation(initblock, None)
+setannotation(newblock, s_Block)
+setannotation(newgraph, s_Graph)
+setannotation(getstartblock, s_Block)
 setannotation(geninputarg, s_ConstOrVar)
+setannotation(getinputarg, s_ConstOrVar)
 setannotation(genop, s_ConstOrVar)
 setannotation(gencallableconst, s_ConstOrVar)
 setannotation(genconst, s_ConstOrVar)
@@ -396,6 +434,8 @@
 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)
 
@@ -405,3 +445,5 @@
 setannotation(constFieldName, s_ConstOrVar, specialize_as_constant=True)
 setannotation(constTYPE,      s_ConstOrVar, specialize_as_constant=True)
 #setannotation(placeholder,    s_ConstOrVar, specialize_as_constant=True)
+
+setannotation(show_incremental_progress, None)

Modified: pypy/dist/pypy/jit/codegen/llgraph/rgenop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/llgraph/rgenop.py	(original)
+++ pypy/dist/pypy/jit/codegen/llgraph/rgenop.py	Thu Sep 28 20:10:20 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,15 @@
         llimpl.closelink(lnk, args_gv, targetblock.b)
 
     def finish_and_return(self, sigtoken, gv_returnvar):
+        gv_returnvar = gv_returnvar or gv_dummy_placeholder
         lnk = self.lnk or llimpl.closeblock1(self.b)
         self.lnk = llimpl.nulllink
-        llimpl.closereturnlink(lnk,
-                               (gv_returnvar or gv_dummy_placeholder).v)
+        llimpl.closereturnlink(lnk, gv_returnvar.v, 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 +153,36 @@
     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
+
+    def show_incremental_progress(self):
+        llimpl.show_incremental_progress(self.g)
+
 
 class RGenOp(AbstractRGenOp):
     gv_Void = gv_Void
 
 
     def newgraph(self, (ARGS_gv, gv_RESULT, gv_FUNCTYPE)):
-        builder = LLBuilder()
-        inputargs_gv = builder._newblock(ARGS_gv)
-        return builder, LLBlock(builder.b), inputargs_gv
-
-    def gencallableconst(self, (ARGS_gv, gv_RESULT, gv_FUNCTYPE), name,
-                         entrypoint):
-        return LLConst(llimpl.gencallableconst(name, entrypoint.b,
+        graph = llimpl.newgraph(gv_FUNCTYPE.v)
+        builder = LLBuilder(graph)
+        builder.b = llimpl.getstartblock(graph)
+        inputargs_gv = [LLVar(llimpl.getinputarg(builder.b, i))
+                        for i in range(len(ARGS_gv))]
+        return builder, graph, inputargs_gv
+
+    def gencallableconst(self, (ARGS_gv, gv_RESULT, gv_FUNCTYPE), name, graph):
+        return LLConst(llimpl.gencallableconst(name, graph,
                                                gv_FUNCTYPE.v))
 
     @staticmethod
@@ -201,6 +228,15 @@
 
     constPrebuiltGlobal = genconst
 
+    def replay(self, block, kinds):
+        builder = LLBuilder(block.g)
+        args_gv = builder._newblock(kinds)
+        return builder, args_gv
+
+    def stop_replay(self, endblock, kinds):
+        return [LLVar(llimpl.getinputarg(endblock.b, i))
+                for i in range(len(kinds))]
+
     # not RPython, just for debugging.  Specific to llgraph.
     @staticmethod
     def reveal(gv):
@@ -210,15 +246,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/dist/pypy/jit/codegen/model.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/model.py	(original)
+++ pypy/dist/pypy/jit/codegen/model.py	Thu Sep 28 20:10:20 2006
@@ -23,3 +23,7 @@
 
 class AbstractRGenOp(object):
     pass
+
+
+class CodeGenSwitch(object):
+    pass

Modified: pypy/dist/pypy/jit/hintannotator/model.py
==============================================================================
--- pypy/dist/pypy/jit/hintannotator/model.py	(original)
+++ pypy/dist/pypy/jit/hintannotator/model.py	Thu Sep 28 20:10:20 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/dist/pypy/jit/timeshifter/rcontainer.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rcontainer.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rcontainer.py	Thu Sep 28 20:10:20 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/dist/pypy/jit/timeshifter/rtimeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtimeshift.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py	Thu Sep 28 20:10:20 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)"
 
@@ -231,8 +241,15 @@
 
 def split(jitstate, switchredbox, resumepoint, *greens_gv):
     exitgvar = switchredbox.getgenvar(jitstate.curbuilder)
-    later_builder = jitstate.curbuilder.jump_if_false(exitgvar)
-    jitstate.split(later_builder, resumepoint, list(greens_gv))
+    if exitgvar.is_const:
+        return exitgvar.revealconst(lltype.Bool)
+    else:
+        if jitstate.resuming is None:
+            later_builder = jitstate.curbuilder.jump_if_false(exitgvar)
+            jitstate.split(later_builder, resumepoint, list(greens_gv))
+            return True
+        else:
+            return jitstate.resuming.path.pop()
 
 def collect_split(jitstate_chain, resumepoint, *greens_gv):
     greens_gv = list(greens_gv)
@@ -304,6 +321,145 @@
 ##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, switchblock, promotion_path):
+        assert promotion_path is not None
+        self.flexswitch = flexswitch
+        self.switchblock = switchblock
+        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)
+        builder.show_incremental_progress()
+
+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:
+        lloperation.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):
+    builder = jitstate.curbuilder
+    gv_switchvar = box.getgenvar(builder)
+    if gv_switchvar.is_const:
+        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:
+            gv_switchvar = box.genvar
+            flexswitch = builder.flexswitch(gv_switchvar)
+            # default case of the switch:
+            enter_block(jitstate)
+            pm = PromotionPoint(flexswitch, switchblock,
+                                jitstate.promotion_path)
+            ll_pm = cast_instance_to_base_ptr(pm)
+            gv_pm = builder.rgenop.genconst(ll_pm)
+            gv_switchvar = box.genvar
+            builder.genop_call(promotiondesc.sigtoken,
+                               promotiondesc.gv_continue_compilation,
+                               [gv_pm, gv_switchvar])
+            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
+
+            kinds = [box.kind for box in incoming]
+            vars_gv = jitstate.curbuilder.rgenop.stop_replay(pm.switchblock,
+                                                             kinds)
+            for i in range(len(incoming)):
+                incoming[i].genvar = vars_gv[i]
+            box.genvar = resuming.gv_value
+
+            newbuilder = pm.flexswitch.add_case(resuming.gv_value)
+
+            jitstate.resuming = None
+            jitstate.promotion_path = pm.promotion_path
+            jitstate.curbuilder = newbuilder
+            enter_block(jitstate)
+            return False
+
 # ____________________________________________________________
 
 class BaseDispatchQueue(object):
@@ -346,6 +502,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 +536,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 +584,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 +603,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 +634,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 +644,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/dist/pypy/jit/timeshifter/rtyper.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtyper.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rtyper.py	Thu Sep 28 20:10:20 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
 
@@ -717,8 +710,9 @@
         args_s += [self.s_ConstOrVar] * len(greens_v)
         args_v = [v_jitstate, v_switch, c_resumepoint]
         args_v += greens_v
-        hop.llops.genmixlevelhelpercall(rtimeshift.split, args_s, args_v,
-                                        annmodel.s_None)
+        return hop.llops.genmixlevelhelpercall(rtimeshift.split,
+                                               args_s, args_v,
+                                               annmodel.SomeBool())
 
     def translate_op_collect_split(self, hop):
         GREENS = [v.concretetype for v in hop.args_v[1:]]
@@ -738,17 +732,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 +769,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 +814,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/dist/pypy/jit/timeshifter/rvalue.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rvalue.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rvalue.py	Thu Sep 28 20:10:20 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

Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py	Thu Sep 28 20:10:20 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)
@@ -272,9 +271,10 @@
         # now try to run the residual graph generated by the builder
         residual_graph = ll_generated._obj.graph
         residual_graph.exceptiontransformed = self.hrtyper.exc_data_ptr
+        self.ll_generated = ll_generated
+        self.residual_graph = residual_graph
         if conftest.option.view:
             residual_graph.show()
-        self.insns = summary(residual_graph)
 
         if 'check_raises' not in kwds:
             res = llinterp.eval_graph(residual_graph, residualargs)
@@ -314,6 +314,7 @@
         return self.timeshift(ll_function, values, opt_consts, *args, **kwds)
 
     def check_insns(self, expected=None, **counts):
+        self.insns = summary(self.residual_graph)
         if expected is not None:
             assert self.insns == expected
         for opname, count in counts.items():

Modified: pypy/dist/pypy/jit/timeshifter/transform.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/transform.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/transform.py	Thu Sep 28 20:10:20 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 = []
@@ -171,6 +192,7 @@
                     self.insert_split_handling(block)
 
     def insert_split_handling(self, block):
+        # lots of clever in-line logic commented out
         v_redswitch = block.exitswitch
         link_f, link_t = block.exits
         if link_f.exitcase:
@@ -178,35 +200,42 @@
         assert link_f.exitcase is False
         assert link_t.exitcase is True
 
-        constant_block = Block([])
-        nonconstant_block = Block([])
+##        constant_block = Block([])
+##        nonconstant_block = Block([])
 
-        v_flag = self.genop(block, 'is_constant', [v_redswitch],
-                            resulttype = lltype.Bool)
-        self.genswitch(block, v_flag, true  = constant_block,
-                                      false = nonconstant_block)
-
-        v_greenswitch = self.genop(constant_block, 'revealconst',
-                                   [v_redswitch],
-                                   resulttype = lltype.Bool)
-        constant_block.exitswitch = v_greenswitch
-        constant_block.closeblock(link_f, link_t)
+##        v_flag = self.genop(block, 'is_constant', [v_redswitch],
+##                            resulttype = lltype.Bool)
+##        self.genswitch(block, v_flag, true  = constant_block,
+##                                      false = nonconstant_block)
+
+##        v_greenswitch = self.genop(constant_block, 'revealconst',
+##                                   [v_redswitch],
+##                                   resulttype = lltype.Bool)
+##        constant_block.exitswitch = v_greenswitch
+##        constant_block.closeblock(link_f, link_t)
 
         reds, greens = self.sort_by_color(link_f.args, link_f.target.inputargs)
-        self.genop(nonconstant_block, 'save_locals', reds)
+        self.genop(block, 'save_locals', reds)
         resumepoint = self.get_resume_point(link_f.target)
         c_resumepoint = inputconst(lltype.Signed, resumepoint)
-        self.genop(nonconstant_block, 'split',
-                   [v_redswitch, c_resumepoint] + greens)
+        v_flag = self.genop(block, 'split',
+                            [v_redswitch, c_resumepoint] + greens,
+                            resulttype = lltype.Bool)
+
+        block.exitswitch = v_flag
+        true_block = Block([])
+        true_link  = Link([], true_block)
+        true_link.exitcase   = True
+        true_link.llexitcase = True
+        block.recloseblock(link_f, true_link)
 
         reds, greens = self.sort_by_color(link_t.args)
-        self.genop(nonconstant_block, 'save_locals', reds)
-        self.genop(nonconstant_block, 'enter_block', [])
-        nonconstant_block.closeblock(Link(link_t.args, link_t.target))
-
-        SSA_to_SSI({block            : True,    # reachable from outside
-                    constant_block   : False,
-                    nonconstant_block: False}, self.hannotator)
+        self.genop(true_block, 'save_locals', reds)
+        self.genop(true_block, 'enter_block', [])
+        true_block.closeblock(Link(link_t.args, link_t.target))
+
+        SSA_to_SSI({block     : True,    # reachable from outside
+                    true_block: False}, self.hannotator)
 
     def get_resume_point_link(self, block):
         try:
@@ -239,6 +268,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 +290,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 +313,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 +357,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 +419,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 +536,53 @@
         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.hannotator.binding(op.result).is_green()
+        assert not self.hannotator.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]
+        v_promote = op.args[0]
+        newop = SpaceOperation('revealconst', [v_promote], 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)
+        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/dist/pypy/rpython/annlowlevel.py
==============================================================================
--- pypy/dist/pypy/rpython/annlowlevel.py	(original)
+++ pypy/dist/pypy/rpython/annlowlevel.py	Thu Sep 28 20:10:20 2006
@@ -347,6 +347,7 @@
         return annmodel.SomePtr(F)
 
     def specialize_call(self, hop):
+        hop.exception_cannot_occur()
         return hop.args_r[1].get_unique_llfn()
 
 # ____________________________________________________________
@@ -372,6 +373,7 @@
     def specialize_call(self, hop):
         v_arg = hop.inputarg(hop.args_r[1], arg=1)
         assert isinstance(v_arg.concretetype, lltype.Ptr)
+        hop.exception_cannot_occur()
         return hop.genop('cast_pointer', [v_arg],
                          resulttype = hop.r_result.lowleveltype)
 
@@ -391,6 +393,7 @@
     def specialize_call(self, hop):
         v_arg = hop.inputarg(hop.args_r[1], arg=1)
         assert isinstance(v_arg.concretetype, lltype.Ptr)
+        hop.exception_cannot_occur()
         return hop.genop('cast_pointer', [v_arg],
                          resulttype = hop.r_result.lowleveltype)
 
@@ -409,11 +412,7 @@
 ##        s_Instance, r_Instance = pol.annhelper.s_r_instanceof(s_Class.const)
 ##        return annmodel.SomePtr(r_Instance.lowleveltype)
 
-##    def specialize_call(self, hop):
-##        v_arg = hop.inputarg(hop.args_r[1], arg=1)
-##        assert isinstance(v_arg.concretetype, lltype.Ptr)
-##        return hop.genop('cast_pointer', [v_arg],
-##                         resulttype = hop.r_result.lowleveltype)
+##    ...
 
 # ____________________________________________________________
 

Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py	(original)
+++ pypy/dist/pypy/rpython/llinterp.py	Thu Sep 28 20:10:20 2006
@@ -27,6 +27,10 @@
             extra = ''
         return '<LLException %r%s>' % (type_name(etype), extra)
 
+class LLFatalError(Exception):
+    def __str__(self):
+        return ': '.join([str(x) for x in self.args])
+
 def type_name(etype):
     if isinstance(lltype.typeOf(etype), lltype.Ptr):
         return ''.join(etype.name).rstrip('\x00')
@@ -442,6 +446,14 @@
         # do nothing, this is useful in compiled code
         pass
 
+    def op_debug_fatalerror(self, ll_msg, ll_exc=None):
+        msg = ''.join(ll_msg.chars)
+        if ll_exc is None:
+            raise LLFatalError(msg)
+        else:
+            ll_exc_type = lltype.cast_pointer(rclass.OBJECTPTR, ll_exc).typeptr
+            raise LLFatalError(msg, LLException(ll_exc_type, ll_exc))
+
     def op_keepalive(self, value):
         pass
 

Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py	Thu Sep 28 20:10:20 2006
@@ -394,6 +394,7 @@
     'debug_pdb':            LLOp(),
     'debug_log_exc':        LLOp(),
     'debug_assert':         LLOp(canfold=True),
+    'debug_fatalerror':     LLOp(),
 }
 
     # __________ operations on PyObjects __________

Modified: pypy/dist/pypy/tool/sourcetools.py
==============================================================================
--- pypy/dist/pypy/tool/sourcetools.py	(original)
+++ pypy/dist/pypy/tool/sourcetools.py	Thu Sep 28 20:10:20 2006
@@ -109,6 +109,8 @@
             src = inspect.getsource(object)
         except IOError:
             return None
+        except IndentationError:
+            return None
     if hasattr(name, "__sourceargs__"):
         return src % name.__sourceargs__
     return src



More information about the Pypy-commit mailing list