[pypy-svn] r32556 - in pypy/dist/pypy: jit/codegen/i386/test jit/hintannotator jit/timeshifter jit/timeshifter/test rpython translator translator/backendopt translator/backendopt/test

ac at codespeak.net ac at codespeak.net
Thu Sep 21 11:30:28 CEST 2006


Author: ac
Date: Thu Sep 21 11:30:27 2006
New Revision: 32556

Added:
   pypy/dist/pypy/jit/timeshifter/transform.py
      - copied unchanged from r32555, pypy/branch/timeshift-refactoring/pypy/jit/timeshifter/transform.py
Removed:
   pypy/dist/pypy/jit/timeshifter/timeshift.py
Modified:
   pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py
   pypy/dist/pypy/jit/hintannotator/annotator.py
   pypy/dist/pypy/jit/hintannotator/bookkeeper.py
   pypy/dist/pypy/jit/hintannotator/model.py
   pypy/dist/pypy/jit/timeshifter/oop.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/vlist.py
   pypy/dist/pypy/rpython/rtyper.py
   pypy/dist/pypy/translator/backendopt/ssa.py
   pypy/dist/pypy/translator/backendopt/test/test_ssa.py
   pypy/dist/pypy/translator/simplify.py
Log:
(arigo, arre) Merging from branch:
svn merge -r 32480:32555 svn+ssh://codespeak.net/svn/pypy/branch/timeshift-refactoring .

Refactoring timeshifting into a graph shape transform and a rtyping phase.

Added a SSA_to_SSI helper to make graph transforming easier. (rev. 32501)

Added support for yellow calls, i.e. calling a function with some red arguments
but getting a green return.



Modified: pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py	(original)
+++ pypy/dist/pypy/jit/codegen/i386/test/test_genc_ts.py	Thu Sep 21 11:30:27 2006
@@ -15,7 +15,7 @@
     SEPLINE = 'running residual graph...\n'
     
     def annotate_interface_functions(self):
-        annhelper = self.htshift.annhelper
+        annhelper = self.hrtyper.annhelper
         RGenOp = self.RGenOp
         SEPLINE = self.SEPLINE
         ml_generate_code = self.ml_generate_code

Modified: pypy/dist/pypy/jit/hintannotator/annotator.py
==============================================================================
--- pypy/dist/pypy/jit/hintannotator/annotator.py	(original)
+++ pypy/dist/pypy/jit/hintannotator/annotator.py	Thu Sep 21 11:30:27 2006
@@ -20,9 +20,6 @@
         flowgraph = desc.specialize(input_args_hs)
         return self.build_graph_types(flowgraph, input_args_hs)
 
-    def simplify(self):
-        pass
-
     def consider_op_malloc(self, hs_TYPE):
         TYPE = hs_TYPE.const
         if getattr(self.policy, 'novirtualcontainer', False):

Modified: pypy/dist/pypy/jit/hintannotator/bookkeeper.py
==============================================================================
--- pypy/dist/pypy/jit/hintannotator/bookkeeper.py	(original)
+++ pypy/dist/pypy/jit/hintannotator/bookkeeper.py	Thu Sep 21 11:30:27 2006
@@ -65,6 +65,7 @@
         self.descs = {}
         self.tsgraph_maximal_call_families = UnionFind(TsGraphCallFamily)
         self.annotator = hannotator
+        self.tsgraphsigs = {}
         # circular imports hack
         global hintmodel
         from pypy.jit.hintannotator import model as hintmodel
@@ -109,7 +110,18 @@
         return origin
 
     def compute_at_fixpoint(self):
-        pass
+        # compute and cache the green-ness of OriginFlags objects
+        # while we can do so (i.e. before the graphs are modified)
+        for origin in self.originflags.values():
+            if origin.spaceop is not None:
+                origin.greenargs_cached = origin.greenargs()
+        # compute and cache the signature of the graphs before they are
+        # modified by further code
+        ha = self.annotator
+        for tsgraph in ha.translator.graphs:
+            sig_hs = ([ha.binding(v) for v in tsgraph.getargs()],
+                      ha.binding(tsgraph.getreturnvar()))
+            self.tsgraphsigs[tsgraph] = sig_hs
 
     def immutableconstant(self, const):
         res = hintmodel.SomeLLAbstractConstant(const.concretetype, {})

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 21 11:30:27 2006
@@ -32,6 +32,8 @@
 
     fixed = False
     read_positions = None
+    greenargs_cached = None
+    is_call_result = False
 
     def __init__(self, bookkeeper=None, spaceop=None):
         self.bookkeeper = bookkeeper
@@ -61,8 +63,10 @@
     def greenargs(self, frame=None):
         annotator = self.bookkeeper.annotator
         if frame is None:
+            if self.greenargs_cached is not None:
+                return self.greenargs_cached
             frame = GreenHandlerFrame(annotator)
-        if self.spaceop.opname == 'direct_call':     # ah haa
+        if self.is_call_result:
             return frame.greencallresult(self.spaceop)
         else:
             for v in self.spaceop.args:
@@ -93,6 +97,8 @@
 ##            import pdb; pdb.set_trace()
         args_hs = [self.annotator.binding(v) for v in spaceop.args]
         hs_result = self.annotator.binding(spaceop.result)
+        if not isinstance(hs_result, SomeLLAbstractConstant):
+            return False     # was generalized, e.g. to SomeLLAbstractVariable
         hs_f1 = args_hs.pop(0)
         fnobj = hs_f1.const._obj
         if (getattr(self.annotator.policy, 'oopspec', False) and
@@ -229,6 +235,12 @@
     else:
         return hs_v1
 
+def originalconcretetype(hs):
+    if isinstance(hs, annmodel.SomeImpossibleValue):
+        return lltype.Void
+    else:
+        return hs.concretetype
+
 # ____________________________________________________________
 # operations
 
@@ -334,6 +346,7 @@
 
         if isinstance(hs_res, SomeLLAbstractConstant):
             hs_res.myorigin = bookkeeper.myorigin()
+            hs_res.myorigin.is_call_result = True
 
         # we need to make sure that hs_res does not become temporarily less
         # general as a result of calling another specialized version of the

Modified: pypy/dist/pypy/jit/timeshifter/oop.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/oop.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/oop.py	Thu Sep 21 11:30:27 2006
@@ -2,6 +2,7 @@
 from pypy.rpython.extregistry import ExtRegistryEntry
 from pypy.jit.timeshifter.rcontainer import cachedtype
 from pypy.jit.timeshifter import rvalue, rtimeshift
+from pypy.translator.c import exceptiontransform
 
 
 class Index:
@@ -13,7 +14,6 @@
     __metaclass__ = cachedtype
 
     def __init__(self, hrtyper, fnobj):
-        ts = hrtyper.timeshifter
         ll_func = fnobj._callable
         FUNCTYPE = lltype.typeOf(fnobj)
         nb_args = len(FUNCTYPE.ARGS)
@@ -45,7 +45,7 @@
         if FUNCTYPE.RESULT is lltype.Void:
             self.errorbox = None
         else:
-            error_value = ts.error_value(FUNCTYPE.RESULT)
+            error_value = exceptiontransform.error_value(FUNCTYPE.RESULT)
             self.errorbox = rvalue.redbox_from_prebuilt_value(RGenOp,
                                                               error_value)
         self.redboxbuilder = rvalue.ll_redboxbuilder(FUNCTYPE.RESULT)
@@ -64,8 +64,9 @@
 
         # exception handling
         graph = fnobj.graph
-        self.can_raise = ts.etrafo.raise_analyzer.analyze_direct_call(graph)
-        self.fetch_global_excdata = ts.fetch_global_excdata
+        etrafo = hrtyper.etrafo
+        self.can_raise = etrafo.raise_analyzer.analyze_direct_call(graph)
+        self.fetch_global_excdata = hrtyper.fetch_global_excdata
 
     def residual_call(self, jitstate, argboxes):
         builder = jitstate.curbuilder

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 21 11:30:27 2006
@@ -1,6 +1,8 @@
 import operator, weakref
 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
 
 FOLDABLE_OPS = dict.fromkeys(lloperation.enum_foldable_ops())
 
@@ -44,8 +46,8 @@
 def make_opdesc(hop):
     hrtyper = hop.rtyper
     op_key = (hrtyper.RGenOp, hop.spaceop.opname,
-              tuple([hrtyper.originalconcretetype(s_arg) for s_arg in hop.args_s]),
-              hrtyper.originalconcretetype(hop.s_result))
+              tuple([originalconcretetype(s_arg) for s_arg in hop.args_s]),
+              originalconcretetype(hop.s_result))
     try:
         return _opdesc_cache[op_key]
     except KeyError:
@@ -193,8 +195,7 @@
     states_dic[key] = frozen, newblock
 start_new_block._annspecialcase_ = "specialize:arglltype(2)"
 
-def retrieve_jitstate_for_merge(states_dic, jitstate, key, redboxes):
-    save_locals(jitstate, redboxes)
+def retrieve_jitstate_for_merge(states_dic, jitstate, key):
     if key not in states_dic:
         start_new_block(states_dic, jitstate, key)
         return False   # continue
@@ -228,38 +229,54 @@
     jitstate.enter_block(incoming, memo)
     enter_next_block(jitstate, incoming)
 
-def leave_block_split(jitstate, switchredbox, exitindex,
-                      redboxes_true, redboxes_false):
-    if switchredbox.is_constant():
-        return rvalue.ll_getvalue(switchredbox, lltype.Bool)
-    else:
-        exitgvar = switchredbox.getgenvar(jitstate.curbuilder)
-        later_builder = jitstate.curbuilder.jump_if_false(exitgvar)
-        save_locals(jitstate, redboxes_false)
-        jitstate.split(later_builder, exitindex)
-        save_locals(jitstate, redboxes_true)
-        enter_block(jitstate)
-        return True
-
-def dispatch_next(oldjitstate, return_cache):
-    split_queue = oldjitstate.frame.split_queue
-    if split_queue:
-        jitstate = split_queue.pop()
+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))
+
+def collect_split(jitstate_chain, resumepoint, *greens_gv):
+    greens_gv = list(greens_gv)
+    pending = jitstate_chain
+    while True:
+        jitstate = pending
+        pending = pending.next
+        jitstate.greens.extend(greens_gv)   # item 0 is the return value
+        jitstate.resumepoint = resumepoint
+        if pending is None:
+            break
+    dispatch_queue = jitstate_chain.frame.dispatch_queue
+    jitstate.next = dispatch_queue.split_chain
+    dispatch_queue.split_chain = jitstate_chain.next
+    # XXX obscurity++ above
+
+def dispatch_next(oldjitstate):
+    dispatch_queue = oldjitstate.frame.dispatch_queue
+    if dispatch_queue.split_chain is not None:
+        jitstate = dispatch_queue.split_chain
+        dispatch_queue.split_chain = jitstate.next
         enter_block(jitstate)
         return jitstate
     else:
-        return leave_graph(oldjitstate.frame.return_queue, return_cache)
+        oldjitstate.resumepoint = -1
+        return oldjitstate
 
-def getexitindex(jitstate):
-    return jitstate.exitindex
+def getresumepoint(jitstate):
+    return jitstate.resumepoint
 
-def save_locals(jitstate, redboxes):
+def save_locals(jitstate, *redboxes):
+    redboxes = list(redboxes)
     assert None not in redboxes
     jitstate.frame.local_boxes = redboxes
 
+def save_greens(jitstate, *greens_gv):
+    jitstate.greens = list(greens_gv)
+
 def getlocalbox(jitstate, i):
     return jitstate.frame.local_boxes[i]
 
+def ll_getgreenbox(jitstate, i, T):
+    return jitstate.greens[i].revealconst(T)
+
 def getreturnbox(jitstate):
     return jitstate.returnbox
 
@@ -276,16 +293,35 @@
     jitstate.exc_value_box = box
 
 def save_return(jitstate):
-    jitstate.frame.return_queue.append(jitstate)
+    # add 'jitstate' to the chain of return-jitstates
+    dispatch_queue = jitstate.frame.dispatch_queue
+    jitstate.next = dispatch_queue.return_chain
+    dispatch_queue.return_chain = jitstate
 
-def ll_gvar_from_redbox(jitstate, redbox):
-    return redbox.getgenvar(jitstate.curbuilder)
+##def ll_gvar_from_redbox(jitstate, redbox):
+##    return redbox.getgenvar(jitstate.curbuilder)
 
-def ll_gvar_from_constant(jitstate, ll_value):
-    return jitstate.curbuilder.rgenop.genconst(ll_value)
+##def ll_gvar_from_constant(jitstate, ll_value):
+##    return jitstate.curbuilder.rgenop.genconst(ll_value)
 
 # ____________________________________________________________
 
+class BaseDispatchQueue(object):
+    def __init__(self):
+        self.split_chain = None
+        self.return_chain = None
+
+def build_dispatch_subclass(attrnames):
+    if len(attrnames) == 0:
+        return BaseDispatchQueue
+    attrnames = unrolling_iterable(attrnames)
+    class DispatchQueue(BaseDispatchQueue):
+        def __init__(self):
+            BaseDispatchQueue.__init__(self)
+            for name in attrnames:
+                setattr(self, name, {})     # the new dicts have various types!
+    return DispatchQueue
+
 
 class FrozenVirtualFrame(object):
     fz_backframe = None
@@ -335,10 +371,9 @@
 
 class VirtualFrame(object):
 
-    def __init__(self, backframe, split_queue, return_queue):
+    def __init__(self, backframe, dispatch_queue):
         self.backframe = backframe
-        self.split_queue = split_queue
-        self.return_queue = return_queue
+        self.dispatch_queue = dispatch_queue
         #self.local_boxes = ... set by callers
 
     def enter_block(self, incoming, memo):
@@ -360,9 +395,7 @@
             newbackframe = None
         else:
             newbackframe = self.backframe.copy(memo)
-        result = VirtualFrame(newbackframe,
-                              self.split_queue,
-                              self.return_queue)
+        result = VirtualFrame(newbackframe, self.dispatch_queue)
         result.local_boxes = [box.copy(memo) for box in self.local_boxes]
         return result
 
@@ -376,23 +409,29 @@
 
 class JITState(object):
     returnbox = None
+    next      = None   # for linked lists
 
     def __init__(self, builder, frame, exc_type_box, exc_value_box,
-                 exitindex=-1):
+                 resumepoint=-1, newgreens=[]):
         self.curbuilder = builder
         self.frame = frame
         self.exc_type_box = exc_type_box
         self.exc_value_box = exc_value_box
-        self.exitindex = exitindex
+        self.resumepoint = resumepoint
+        self.greens = newgreens
 
-    def split(self, newbuilder, newexitindex):
+    def split(self, newbuilder, newresumepoint, newgreens):
         memo = rvalue.copy_memo()
         later_jitstate = JITState(newbuilder,
                                   self.frame.copy(memo),
                                   self.exc_type_box .copy(memo),
                                   self.exc_value_box.copy(memo),
-                                  newexitindex)
-        self.frame.split_queue.append(later_jitstate)
+                                  newresumepoint,
+                                  newgreens)
+        # 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
+        dispatch_queue.split_chain = later_jitstate
 
     def enter_block(self, incoming, memo):
         self.frame.enter_block(incoming, memo)
@@ -412,21 +451,50 @@
         self.exc_value_box = self.exc_value_box.replace(memo)
 
 
-def enter_graph(jitstate):
-    jitstate.frame = VirtualFrame(jitstate.frame, [], [])
-
-def leave_graph(return_queue, return_cache):
-    for jitstate in return_queue[:-1]:
-        res = retrieve_jitstate_for_merge(return_cache, jitstate, (),
-                                          # XXX strange next argument
-                                          jitstate.frame.local_boxes)
+def enter_graph(jitstate, DispatchQueueClass):
+    jitstate.frame = VirtualFrame(jitstate.frame, DispatchQueueClass())
+enter_graph._annspecialcase_ = 'specialize:arg(1)'
+# XXX is that too many specializations? ^^^
+
+def merge_returning_jitstates(jitstate):
+    return_chain = jitstate.frame.dispatch_queue.return_chain
+    return_cache = {}
+    still_pending = None
+    while return_chain is not None:
+        jitstate = return_chain
+        return_chain = return_chain.next
+        res = retrieve_jitstate_for_merge(return_cache, jitstate, ())
+        if res is False:    # not finished
+            jitstate.next = still_pending
+            still_pending = jitstate
+    assert still_pending is not None
+    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, ())
         assert res is True   # finished
-    frozen, block = return_cache[()]
-    jitstate = return_queue[-1]
+    return most_general_jitstate
+
+def leave_graph_red(jitstate):
+    jitstate = merge_returning_jitstates(jitstate)
     myframe = jitstate.frame
-    if myframe.local_boxes:             # else it's a green Void return
-        jitstate.returnbox = myframe.local_boxes[0]
-        # ^^^ fetched by a 'fetch_return' operation
+    jitstate.returnbox = myframe.local_boxes[0]
+    # ^^^ fetched by a 'fetch_return' operation
     jitstate.frame = myframe.backframe
-    jitstate.exitindex = -1
     return jitstate
+
+def leave_graph_void(jitstate):
+    jitstate = merge_returning_jitstates(jitstate)
+    myframe = jitstate.frame
+    jitstate.frame = myframe.backframe
+    return jitstate
+
+def leave_graph_yellow(jitstate):
+    return_chain = jitstate.frame.dispatch_queue.return_chain
+    jitstate = return_chain
+    while jitstate is not None:
+        jitstate.frame = jitstate.frame.backframe
+        jitstate = jitstate.next
+    return return_chain    # a jitstate, which is the head of the chain

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 21 11:30:27 2006
@@ -10,7 +10,10 @@
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.jit.hintannotator import model as hintmodel
 from pypy.jit.hintannotator import container as hintcontainer
-from pypy.jit.timeshifter import rtimeshift, rvalue, rcontainer
+from pypy.jit.hintannotator.model import originalconcretetype
+from pypy.jit.timeshifter import rtimeshift, rvalue, rcontainer, oop
+from pypy.jit.timeshifter.transform import HintGraphTransformer
+from pypy.jit.codegen import model as cgmodel
 
 class HintTypeSystem(LowLevelTypeSystem):
     name = "hinttypesystem"
@@ -36,27 +39,156 @@
 # ___________________________________________________________
 
 
-def originalconcretetype(hs):
-    if isinstance(hs, annmodel.SomeImpossibleValue):
-        return lltype.Void
-    else:
-        return hs.concretetype
-
 class HintRTyper(RPythonTyper):
 
-    def __init__(self, hannotator, timeshifter):
+    def __init__(self, hannotator, rtyper, RGenOp):
         RPythonTyper.__init__(self, hannotator, 
                               type_system=HintTypeSystem.instance)
+        self.rtyper = rtyper
+        self.RGenOp = RGenOp
         self.green_reprs = PRECOMPUTED_GREEN_REPRS.copy()
         self.red_reprs = {}
-        self.color_cache = {}
-        self.timeshifter = timeshifter
-        self.RGenOp = timeshifter.RGenOp
+        #self.color_cache = {}
+
+        self.annhelper = annlowlevel.MixLevelHelperAnnotator(rtyper)
+        self.timeshift_mapping = {}
+        self.sigs = {}
+        self.dispatchsubclasses = {}
+
+        (self.s_CodeGenerator,
+         self.r_CodeGenerator) = self.s_r_instanceof(cgmodel.CodeGenerator)
+        (self.s_JITState,
+         self.r_JITState)      = self.s_r_instanceof(rtimeshift.JITState)
+        (self.s_RedBox,
+         self.r_RedBox)        = self.s_r_instanceof(rvalue.RedBox)
+        (self.s_OopSpecDesc,
+         self.r_OopSpecDesc)   = self.s_r_instanceof(oop.OopSpecDesc)
+        (self.s_ConstOrVar,
+         self.r_ConstOrVar)    = self.s_r_instanceof(cgmodel.GenVarOrConst)
+        (self.s_Block,
+         self.r_Block)         = self.s_r_instanceof(cgmodel.CodeGenBlock)
+
+        self.etrafo = hannotator.exceptiontransformer
+        self.cexcdata = self.etrafo.cexcdata
+        self.exc_data_ptr = self.cexcdata.value
+        gv_excdata = RGenOp.constPrebuiltGlobal(self.exc_data_ptr)
+        LL_EXC_TYPE  = rtyper.exceptiondata.lltype_of_exception_type
+        LL_EXC_VALUE = rtyper.exceptiondata.lltype_of_exception_value
+        null_exc_type_box = rvalue.redbox_from_prebuilt_value(RGenOp,
+                                         lltype.nullptr(LL_EXC_TYPE.TO))
+        null_exc_value_box = rvalue.redbox_from_prebuilt_value(RGenOp,
+                                         lltype.nullptr(LL_EXC_VALUE.TO))
+
+        p = self.etrafo.rpyexc_fetch_type_ptr.value
+        gv_rpyexc_fetch_type = RGenOp.constPrebuiltGlobal(p)
+        tok_fetch_type = RGenOp.sigToken(lltype.typeOf(p).TO)
+        kind_etype = RGenOp.kindToken(LL_EXC_TYPE)
+
+        p = self.etrafo.rpyexc_fetch_value_ptr.value
+        gv_rpyexc_fetch_value = RGenOp.constPrebuiltGlobal(p)
+        tok_fetch_value = RGenOp.sigToken(lltype.typeOf(p).TO)
+        kind_evalue = RGenOp.kindToken(LL_EXC_VALUE)
+
+        p = self.etrafo.rpyexc_clear_ptr.value
+        gv_rpyexc_clear = RGenOp.constPrebuiltGlobal(p)
+        tok_clear = RGenOp.sigToken(lltype.typeOf(p).TO)
+
+        p = self.etrafo.rpyexc_raise_ptr.value
+        gv_rpyexc_raise = RGenOp.constPrebuiltGlobal(p)
+        tok_raise = RGenOp.sigToken(lltype.typeOf(p).TO)
+
+        def fetch_global_excdata(jitstate):
+            builder = jitstate.curbuilder
+            gv_etype = builder.genop_call(tok_fetch_type,
+                                          gv_rpyexc_fetch_type, [])
+            gv_evalue = builder.genop_call(tok_fetch_value,
+                                           gv_rpyexc_fetch_value, [])
+            builder.genop_call(tok_clear, gv_rpyexc_clear, [])
+            etypebox  = rvalue.PtrRedBox(kind_etype,  gv_etype)
+            evaluebox = rvalue.PtrRedBox(kind_evalue, gv_evalue)
+            rtimeshift.setexctypebox (jitstate, etypebox)
+            rtimeshift.setexcvaluebox(jitstate, evaluebox)
+        self.fetch_global_excdata = fetch_global_excdata
+
+        def store_global_excdata(jitstate):
+            builder = jitstate.curbuilder
+            etypebox = jitstate.exc_type_box
+            if etypebox.is_constant():
+                ll_etype = rvalue.ll_getvalue(etypebox, llmemory.Address)
+                if not ll_etype:
+                    return       # we known there is no exception set
+            evaluebox = jitstate.exc_value_box
+            gv_etype  = etypebox .getgenvar(builder)
+            gv_evalue = evaluebox.getgenvar(builder)
+            builder.genop_call(tok_raise,
+                               gv_rpyexc_raise, [gv_etype, gv_evalue])
+        self.store_global_excdata = store_global_excdata
+
+        def ll_fresh_jitstate(builder):
+            return rtimeshift.JITState(builder, None,
+                                       null_exc_type_box,
+                                       null_exc_value_box)
+        self.ll_fresh_jitstate = ll_fresh_jitstate
+
+        def ll_finish_jitstate(jitstate, graphsigtoken):
+            returnbox = rtimeshift.getreturnbox(jitstate)
+            gv_ret = returnbox.getgenvar(jitstate.curbuilder)
+            store_global_excdata(jitstate)
+            jitstate.curbuilder.finish_and_return(graphsigtoken, gv_ret)
+        self.ll_finish_jitstate = ll_finish_jitstate
+
+    def specialize(self, view=False):
+        """
+        Driver for running the timeshifter.
+        """
+        graphs = self.annotator.translator.graphs
+        if view:
+            for graph in graphs:
+                self.transform_graph(graph)
+            self.annotator.translator.view()     # in the middle
+            for graph in graphs:
+                self.timeshift_graph(graph)
 
-    originalconcretetype = staticmethod(originalconcretetype)
+        else:
+            # do the whole transformation graph-by-graph if there is no
+            # need to view the intermediate result
+            for graph in graphs:
+                self.transform_graph(graph)
+                self.timeshift_graph(graph)
+
+    def transform_graph(self, graph):
+        # prepare the graphs by inserting all bookkeeping/dispatching logic
+        # as special operations
+        assert graph.startblock in self.annotator.annotated
+        transformer = HintGraphTransformer(self.annotator, graph)
+        transformer.transform()
+        flowmodel.checkgraph(graph)    # for now
+
+    def timeshift_graph(self, graph):
+        # specialize all blocks of this graph
+        for block in graph.iterblocks():
+            self.annotator.annotated[block] = graph
+            self.specialize_block(block)
+        # "normalize" the graphs by putting an explicit v_jitstate variable
+        # everywhere
+        self.insert_v_jitstate_everywhere(graph)
+        # the graph is now timeshifted, so it is *itself* no longer
+        # exception-transformed...
+        del graph.exceptiontransformed
+
+    # ____________________________________________________________
+
+    def s_r_instanceof(self, cls, can_be_None=True):
+        # Return a SomeInstance / InstanceRepr pair correspnding to the specified class.
+        return self.annhelper.s_r_instanceof(cls, can_be_None=can_be_None)
+
+    def get_sig_hs(self, tsgraph):
+        # the signature annotations are cached on the HintBookkeeper because
+        # the graph is transformed already
+        return self.annotator.bookkeeper.tsgraphsigs[tsgraph]
 
     def make_new_lloplist(self, block):
-        return HintLowLevelOpList(self.timeshifter)
+        return HintLowLevelOpList(self)
 
     def getgreenrepr(self, lowleveltype):
         try:
@@ -75,20 +207,65 @@
             if isinstance(lowleveltype, lltype.Ptr):
                 if isinstance(lowleveltype.TO, lltype.Struct):
                     redreprcls = RedStructRepr
-            r = redreprcls(lowleveltype, self.timeshifter)
+            r = redreprcls(lowleveltype, self)
             self.red_reprs[lowleveltype] = r
             return r
 
-    def gethscolor(self, hs):
+##    def gethscolor(self, hs):
+##        try:
+##            return self.color_cache[id(hs)]
+##        except KeyError:
+##            if hs.is_green():
+##                color = "green"
+##            else:
+##                color = "red"
+##            self.color_cache[id(hs)] = color
+##            return color
+
+    def get_dispatch_subclass(self, mergepointfamily):
         try:
-            return self.color_cache[id(hs)]
+            return self.dispatchsubclasses[mergepointfamily]
         except KeyError:
-            if hs.is_green():
-                color = "green"
-            else:
-                color = "red"
-            self.color_cache[id(hs)] = color
-            return color
+            attrnames = mergepointfamily.getattrnames()
+            subclass = rtimeshift.build_dispatch_subclass(attrnames)
+            self.dispatchsubclasses[mergepointfamily] = subclass
+            return subclass
+
+    def get_timeshifted_fnptr(self, graph, specialization_key):
+        bk = self.annotator.bookkeeper
+        tsgraph = bk.get_graph_by_key(graph, specialization_key)
+        args_hs, hs_res = self.get_sig_hs(tsgraph)
+        args_r = [self.getrepr(hs_arg) for hs_arg in args_hs]
+        ARGS = [self.r_JITState.lowleveltype]
+        ARGS += [r.lowleveltype for r in args_r]
+        RESULT = self.r_JITState.lowleveltype
+        fnptr = lltype.functionptr(lltype.FuncType(ARGS, RESULT),
+                                   tsgraph.name,
+                                   graph=tsgraph,
+                                   _callable = graph.func)
+        return fnptr, args_r
+
+    def insert_v_jitstate_everywhere(self, graph):
+        from pypy.translator.unsimplify import varoftype
+        for block in graph.iterblocks():
+            v_jitstate = varoftype(self.r_JITState.lowleveltype, 'jitstate')
+            if block is graph.returnblock:
+                assert block.inputargs[0].concretetype is lltype.Void
+                del block.inputargs[0]
+            block.inputargs = [v_jitstate] + block.inputargs
+            for op in block.operations:
+                if op.opname == 'getjitstate':
+                    op.opname = 'same_as'
+                    op.args = [v_jitstate]
+                elif op.opname == 'setjitstate':
+                    [v_jitstate] = op.args
+            for i in range(len(block.operations)-1, -1, -1):
+                if block.operations[i].opname == 'setjitstate':
+                    del block.operations[i]
+            for link in block.exits:
+                if link.target is graph.returnblock:
+                    del link.args[0]    # Void
+                link.args = [v_jitstate] + link.args
 
     def generic_translate_operation(self, hop, force=False):
         # detect constant-foldable all-green operations
@@ -114,7 +291,7 @@
             ll_generate = rtimeshift.ll_gen1
         elif opdesc.nb_args == 2:
             ll_generate = rtimeshift.ll_gen2
-        ts = self.timeshifter
+        ts = self
         c_opdesc = inputconst(lltype.Void, opdesc)
         s_opdesc = ts.rtyper.annotator.bookkeeper.immutablevalue(opdesc)
         v_jitstate = hop.llops.getjitstate()
@@ -133,7 +310,7 @@
             T = originalconcretetype(hop.args_s[0])
             v_redbox = hop.inputarg(self.getredrepr(T), arg=0)
             assert isinstance(hop.r_result, GreenRepr)
-            ts = self.timeshifter
+            ts = self
             c_T = hop.inputconst(lltype.Void, T)
             s_T = ts.rtyper.annotator.bookkeeper.immutablevalue(T)
             s_res = annmodel.lltype_to_annotation(T)
@@ -157,7 +334,7 @@
     def translate_op_getfield(self, hop):
         if isinstance(hop.args_r[0], BlueRepr):
             return hop.args_r[0].timeshift_getfield(hop)
-        ts = self.timeshifter
+        ts = self
         if hop.args_v[0] == ts.cexcdata:
             # reading one of the exception boxes (exc_type or exc_value)
             fieldname = hop.args_v[1].value
@@ -198,7 +375,7 @@
             if res is not None:
                 return res
 
-        ts = self.timeshifter
+        ts = self
         v_argbox, v_index = hop.inputargs(self.getredrepr(PTRTYPE),
                                           self.getredrepr(lltype.Signed))
         fielddesc = rcontainer.ArrayFieldDesc(self.RGenOp, PTRTYPE.TO)
@@ -217,7 +394,7 @@
             return res
         
         PTRTYPE = originalconcretetype(hop.args_s[0])
-        ts = self.timeshifter
+        ts = self
         [v_argbox] = hop.inputargs(self.getredrepr(PTRTYPE))
         
         fielddesc = rcontainer.ArrayFieldDesc(self.RGenOp, PTRTYPE.TO)
@@ -234,7 +411,7 @@
     def translate_op_setfield(self, hop):
         if isinstance(hop.args_r[0], BlueRepr):
             return hop.args_r[0].timeshift_setfield(hop)
-        ts = self.timeshifter        
+        ts = self
         PTRTYPE = originalconcretetype(hop.args_s[0])
         VALUETYPE = originalconcretetype(hop.args_s[2])
         if hop.args_v[0] == ts.cexcdata:
@@ -271,7 +448,7 @@
     def translate_op_setarrayitem(self, hop):
         PTRTYPE = originalconcretetype(hop.args_s[0])
         VALUETYPE = PTRTYPE.TO.OF
-        ts = self.timeshifter
+        ts = self
         v_argbox, v_index, v_valuebox= hop.inputargs(self.getredrepr(PTRTYPE),
                                                      self.getredrepr(lltype.Signed),
                                                      self.getredrepr(VALUETYPE))
@@ -287,7 +464,7 @@
     def translate_op_getsubstruct(self, hop):
         ##if isinstance(hop.args_r[0], BlueRepr):
         ##    return hop.args_r[0].timeshift_getsubstruct(hop)
-        ts = self.timeshifter
+        ts = self
         PTRTYPE = originalconcretetype(hop.args_s[0])
         v_argbox, c_fieldname = hop.inputargs(self.getredrepr(PTRTYPE),
                                               green_void_repr)
@@ -311,7 +488,7 @@
         return r_result.create(hop)
 
     def translate_op_malloc_varsize(self, hop):
-        ts = self.timeshifter
+        ts = self
         assert isinstance(hop.r_result, RedRepr)
         PTRTYPE = originalconcretetype(hop.s_result)
         TYPE = PTRTYPE.TO
@@ -329,7 +506,7 @@
         
         
     def translate_op_ptr_nonzero(self, hop, reverse=False):
-        ts = self.timeshifter
+        ts = self
         PTRTYPE = originalconcretetype(hop.args_s[0])
         v_argbox, = hop.inputargs(self.getredrepr(PTRTYPE))
         v_jitstate = hop.llops.getjitstate()
@@ -343,35 +520,10 @@
         return self.translate_op_ptr_nonzero(hop, reverse=True)
 
 
-    def guess_call_kind(self, spaceop):
-        if spaceop.opname == 'indirect_call':
-            return 'red'  # for now
-        assert spaceop.opname == 'direct_call'
-        c_func = spaceop.args[0]
-        fnobj = c_func.value._obj
-        s_result = self.annotator.binding(spaceop.result)
-        r_result = self.getrepr(s_result)
-        if hasattr(fnobj._callable, 'oopspec'):
-            return 'oopspec'
-        elif (originalconcretetype(s_result) is not lltype.Void and
-              isinstance(r_result, GreenRepr)):
-            for v in spaceop.args:
-                s_arg = self.annotator.binding(v)
-                r_arg = self.getrepr(s_arg)
-                if not isinstance(r_arg, GreenRepr):
-                    return 'yellow'
-            return 'green'
-        else:
-            return 'red'
-
-    def translate_op_direct_call(self, hop):
-        kind = self.guess_call_kind(hop.spaceop)
-        meth = getattr(self, 'handle_%s_call' % (kind,))
-        return meth(hop)
-
     def translate_op_indirect_call(self, hop):
+        XXX
         bk = self.annotator.bookkeeper
-        ts = self.timeshifter
+        ts = self
         v_jitstate = hop.llops.getjitstate()
         v_funcbox = hop.args_v[0]
         graph_list = hop.args_v[-1].value
@@ -396,32 +548,221 @@
         v_newjitstate = hop.genop('indirect_call', args_v, RESULT)
         hop.llops.setjitstate(v_newjitstate)
 
+    # special operations inserted by the HintGraphTransformer
+
+    def translate_op_enter_graph(self, hop):
+        mpfamily = hop.args_v[0].value
+        subclass = self.get_dispatch_subclass(mpfamily)
+        s_subclass = self.rtyper.annotator.bookkeeper.immutablevalue(subclass)
+        c_subclass = inputconst(lltype.Void, subclass)
+        v_jitstate = hop.llops.getjitstate()
+        hop.llops.genmixlevelhelpercall(rtimeshift.enter_graph,
+                                        [self.s_JITState, s_subclass],
+                                        [v_jitstate     , c_subclass],
+                                        annmodel.s_None)
+
+    def translate_op_leave_graph_red(self, hop):
+        v_jitstate = hop.llops.getjitstate()
+        v_newjs = hop.llops.genmixlevelhelpercall(rtimeshift.leave_graph_red,
+                                                  [self.s_JITState],
+                                                  [v_jitstate     ],
+                                                  self.s_JITState)
+        hop.llops.setjitstate(v_newjs)
+
+    def translate_op_leave_graph_void(self, hop):
+        v_jitstate = hop.llops.getjitstate()
+        v_newjs = hop.llops.genmixlevelhelpercall(rtimeshift.leave_graph_void,
+                                                  [self.s_JITState],
+                                                  [v_jitstate     ],
+                                                  self.s_JITState)
+        hop.llops.setjitstate(v_newjs)
+
+    def translate_op_leave_graph_yellow(self, hop):
+        v_jitstate = hop.llops.getjitstate()
+        v_njs = hop.llops.genmixlevelhelpercall(rtimeshift.leave_graph_yellow,
+                                                [self.s_JITState],
+                                                [v_jitstate     ],
+                                                self.s_JITState)
+        hop.llops.setjitstate(v_njs)
 
     def translate_op_save_locals(self, hop):
-        ts = self.timeshifter
         v_jitstate = hop.llops.getjitstate()
-        v_boxes = ts.build_box_list(hop.llops, hop.args_v)
+        boxes_r = [self.getredrepr(originalconcretetype(hs))
+                   for hs in hop.args_s]
+        boxes_v = hop.inputargs(*boxes_r)
+        boxes_s = [self.s_RedBox] * len(hop.args_v)
         hop.llops.genmixlevelhelpercall(rtimeshift.save_locals,
-                                        [ts.s_JITState, ts.s_box_list],
-                                        [v_jitstate,    v_boxes],
+                                        [self.s_JITState] + boxes_s,
+                                        [v_jitstate     ] + boxes_v,
+                                        annmodel.s_None)
+
+    def translate_op_save_greens(self, hop):
+        v_jitstate = hop.llops.getjitstate()
+        greens_v = list(self.wrap_green_vars(hop.llops, hop.args_v))
+        greens_s = [self.s_ConstOrVar] * len(greens_v)
+        return hop.llops.genmixlevelhelpercall(rtimeshift.save_greens,
+                                               [self.s_JITState] + greens_s,
+                                               [v_jitstate     ] + greens_v,
+                                               annmodel.s_None)
+
+    def translate_op_enter_block(self, hop):
+        v_jitstate = hop.llops.getjitstate()
+        hop.llops.genmixlevelhelpercall(rtimeshift.enter_block,
+                                        [self.s_JITState],
+                                        [v_jitstate     ],
                                         annmodel.s_None)
 
     def translate_op_restore_local(self, hop):
-        ts = self.timeshifter
         assert isinstance(hop.args_v[0], flowmodel.Constant)
         index = hop.args_v[0].value
+        c_index = hop.inputconst(lltype.Signed, index)
         v_jitstate = hop.llops.getjitstate()
-        return ts.read_out_box(hop.llops, v_jitstate, index)
+        return hop.llops.genmixlevelhelpercall(rtimeshift.getlocalbox,
+                    [self.s_JITState, annmodel.SomeInteger(nonneg=True)],
+                    [v_jitstate     , c_index                          ],
+                    self.s_RedBox)
+
+    def translate_op_restore_green(self, hop):
+        assert isinstance(hop.args_v[0], flowmodel.Constant)
+        index = hop.args_v[0].value
+        c_index = hop.inputconst(lltype.Signed, index)
+        TYPE = originalconcretetype(hop.s_result)
+        s_TYPE = self.rtyper.annotator.bookkeeper.immutablevalue(TYPE)
+        c_TYPE = hop.inputconst(lltype.Void, TYPE)
+        s_result = annmodel.lltype_to_annotation(TYPE)
+        v_jitstate = hop.llops.getjitstate()
+        return hop.llops.genmixlevelhelpercall(rtimeshift.ll_getgreenbox,
+                  [self.s_JITState, annmodel.SomeInteger(nonneg=True), s_TYPE],
+                  [v_jitstate     , c_index                          , c_TYPE],
+                  s_result)
 
     def translate_op_fetch_return(self, hop):
-        ts = self.timeshifter
+        ts = self
         v_jitstate = hop.llops.getjitstate()
         return hop.llops.genmixlevelhelpercall(rtimeshift.getreturnbox,
                                                [ts.s_JITState],
                                                [v_jitstate   ],
                                                ts.s_RedBox)
 
-    def handle_oopspec_call(self, hop):
+    def translate_op_is_constant(self, hop):
+        hs = hop.args_s[0]
+        r_arg = self.getredrepr(originalconcretetype(hs))
+        [v_arg] = hop.inputargs(r_arg)
+        return hop.llops.genmixlevelhelpercall(rvalue.ll_is_constant,
+                                               [self.s_RedBox],
+                                               [v_arg        ],
+                                               annmodel.SomeBool())
+
+    def translate_op_revealconst(self, hop):
+        hs = hop.args_s[0]
+        TYPE = originalconcretetype(hs)
+        r_arg = self.getredrepr(TYPE)
+        [v_arg] = hop.inputargs(r_arg)
+        s_TYPE = self.rtyper.annotator.bookkeeper.immutablevalue(TYPE)
+        c_TYPE = hop.inputconst(lltype.Void, TYPE)
+        s_result = annmodel.lltype_to_annotation(TYPE)
+        return hop.llops.genmixlevelhelpercall(rvalue.ll_getvalue,
+                                               [self.s_RedBox, s_TYPE],
+                                               [v_arg        , c_TYPE],
+                                               s_result)
+
+    def wrap_green_vars(self, llops, vars):
+        v_jitstate = llops.getjitstate()
+        for var in vars:
+            s_var = annmodel.lltype_to_annotation(var.concretetype)
+            yield llops.genmixlevelhelpercall(rvalue.ll_gv_fromvalue,
+                                              [self.s_JITState, s_var],
+                                              [v_jitstate,      var  ],
+                                              self.s_ConstOrVar)
+
+    def translate_op_split(self, hop):
+        r_switch = self.getredrepr(lltype.Bool)
+        GREENS = [v.concretetype for v in hop.args_v[2:]]
+        greens_r = [self.getgreenrepr(TYPE) for TYPE in GREENS]
+        vlist = hop.inputargs(r_switch, lltype.Signed, *greens_r)
+
+        v_jitstate = hop.llops.getjitstate()
+        v_switch = vlist[0]
+        c_resumepoint = vlist[1]
+        greens_v = list(self.wrap_green_vars(hop.llops, vlist[2:]))
+
+        s_Int = annmodel.SomeInteger(nonneg=True)
+        args_s = [self.s_JITState, self.s_RedBox, s_Int]
+        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)
+
+    def translate_op_collect_split(self, hop):
+        GREENS = [v.concretetype for v in hop.args_v[1:]]
+        greens_r = [self.getgreenrepr(TYPE) for TYPE in GREENS]
+        vlist = hop.inputargs(lltype.Signed, *greens_r)
+
+        v_jitstate = hop.llops.getjitstate()
+        c_resumepoint = vlist[0]
+        greens_v = list(self.wrap_green_vars(hop.llops, vlist[1:]))
+
+        s_Int = annmodel.SomeInteger(nonneg=True)
+        args_s = [self.s_JITState, s_Int]
+        args_s += [self.s_ConstOrVar] * len(greens_v)
+        args_v = [v_jitstate, c_resumepoint]
+        args_v += greens_v
+        hop.llops.genmixlevelhelpercall(rtimeshift.collect_split,
+                                        args_s, args_v,
+                                        annmodel.s_None)
+
+    def translate_op_merge_point(self, hop):
+        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)
+
+        greens_v = []
+        greens_s = []
+        for r, v in zip(hop.args_r[2:], hop.args_v[2:]):
+            s_precise_type = r.annotation()
+            s_erased_type  = r.erased_annotation()
+            r_precise_type = self.rtyper.getrepr(s_precise_type)
+            r_erased_type  = self.rtyper.getrepr(s_erased_type)
+            greens_v.append(hop.llops.convertvar(v, r_precise_type,
+                                                    r_erased_type))
+            greens_s.append(s_erased_type)
+
+        v_jitstate = hop.llops.getjitstate()
+        return hop.llops.genmixlevelhelpercall(merge_point,
+                             [self.s_JITState] + greens_s,
+                             [v_jitstate     ] + greens_v,
+                             annmodel.SomeBool())
+
+    def translate_op_save_return(self, hop):
+        v_jitstate = hop.llops.getjitstate()
+        return hop.llops.genmixlevelhelpercall(rtimeshift.save_return,
+                                               [self.s_JITState],
+                                               [v_jitstate     ],
+                                               annmodel.s_None)
+
+    def translate_op_dispatch_next(self, hop):
+        v_jitstate = hop.llops.getjitstate()
+        v_newjs = hop.llops.genmixlevelhelpercall(rtimeshift.dispatch_next,
+                                                  [self.s_JITState],
+                                                  [v_jitstate     ],
+                                                  self.s_JITState)
+        hop.llops.setjitstate(v_newjs)
+        return hop.llops.genmixlevelhelpercall(rtimeshift.getresumepoint,
+                                               [self.s_JITState],
+                                               [v_newjs        ],
+                                               annmodel.SomeInteger())
+
+    # handling of the various kinds of calls
+
+    def translate_op_oopspec_call(self, hop):
         # special-cased call, for things like list methods
         from pypy.jit.timeshifter.oop import OopSpecDesc, Index
 
@@ -442,7 +783,7 @@
 
         # if the ll_handler() takes more arguments, it must be 'None' defaults.
         # Pass them as constant Nones.
-        ts = self.timeshifter
+        ts = self
         ll_handler = oopspecdesc.ll_handler
         missing_args = ((ll_handler.func_code.co_argcount - 2) -
                         len(oopspecdesc.argtuple))
@@ -470,17 +811,15 @@
                                       [v_jitstate,    c_oopspecdesc] + args_v,
                                       s_result)
 
-    def handle_green_call(self, hop):
-        # green-returning call, for now (XXX) we assume it's an
-        # all-green function that we can just call
+    def translate_op_green_call(self, hop):
         for r_arg in hop.args_r:
             assert isinstance(r_arg, GreenRepr)
         v = hop.genop('direct_call', hop.args_v, hop.r_result.lowleveltype)
         return v
 
-    def handle_red_call(self, hop):
+    def translate_op_red_call(self, hop):
         bk = self.annotator.bookkeeper
-        ts = self.timeshifter
+        ts = self
         v_jitstate = hop.llops.getjitstate()
         c_func = hop.args_v[0]
         fnobj = c_func.value._obj
@@ -496,14 +835,16 @@
         v_newjitstate = hop.genop('direct_call', args_v, RESULT)
         hop.llops.setjitstate(v_newjitstate)
 
+    translate_op_yellow_call = translate_op_red_call
+
 
 class HintLowLevelOpList(LowLevelOpList):
     """Warning: the HintLowLevelOpList's rtyper is the *original*
     rtyper, while the HighLevelOp's rtyper is actually our HintRTyper...
     """
-    def __init__(self, timeshifter):
-        LowLevelOpList.__init__(self, timeshifter.rtyper)
-        self.timeshifter = timeshifter
+    def __init__(self, hrtyper):
+        LowLevelOpList.__init__(self, hrtyper.rtyper)
+        self.hrtyper = hrtyper
 
     def hasparentgraph(self):
         return False   # for now
@@ -524,23 +865,22 @@
                 args_v = [v_self] + args_v
             function = function.im_func
 
-        graph = self.timeshifter.annhelper.getgraph(function, args_s, s_result)
+        graph = self.hrtyper.annhelper.getgraph(function, args_s, s_result)
         self.record_extra_call(graph) # xxx
 
-        c = self.timeshifter.annhelper.graph2const(graph)
+        c = self.hrtyper.annhelper.graph2const(graph)
 
         # build the 'direct_call' operation
-        rtyper = self.timeshifter.rtyper
         try:
             RESULT = annmodel.annotation_to_lltype(s_result)
         except ValueError:
-            RESULT = rtyper.getrepr(s_result).lowleveltype
+            RESULT = self.rtyper.getrepr(s_result).lowleveltype
         return self.genop('direct_call', [c]+args_v,
                           resulttype = RESULT)
 
     def getjitstate(self):
         return self.genop('getjitstate', [],
-                          resulttype = self.timeshifter.r_JITState)
+                          resulttype = self.hrtyper.r_JITState)
 
     def setjitstate(self, v_newjitstate):
         self.genop('setjitstate', [v_newjitstate])
@@ -550,14 +890,14 @@
 class __extend__(pairtype(HintTypeSystem, hintmodel.SomeLLAbstractValue)):
 
     def rtyper_makerepr((ts, hs_c), hrtyper):
-        if hrtyper.gethscolor(hs_c) == 'green':
+        if hs_c.is_green():
             return hrtyper.getgreenrepr(hs_c.concretetype)
         else:
             return hrtyper.getredrepr(hs_c.concretetype)
 
     def rtyper_makekey((ts, hs_c), hrtyper):
-        color = hrtyper.gethscolor(hs_c)
-        return hs_c.__class__, color, hs_c.concretetype
+        is_green = hs_c.is_green()
+        return hs_c.__class__, is_green, hs_c.concretetype
 
 class __extend__(pairtype(HintTypeSystem, hintmodel.SomeLLAbstractContainer)):
 
@@ -568,7 +908,7 @@
             # fall back to a red repr
             return hrtyper.getredrepr(hs_container.concretetype)
         return BlueStructRepr(hs_container.concretetype, vstructdef,
-                              hrtyper.timeshifter)
+                              hrtyper)
 
     def rtyper_makekey((ts, hs_container), hrtyper):        
         vstructdef = hs_container.contentdef
@@ -597,26 +937,26 @@
         return hs_c.__class__,
 
 class RedRepr(Repr):
-    def __init__(self, original_concretetype, timeshifter):
+    def __init__(self, original_concretetype, hrtyper):
         assert original_concretetype is not lltype.Void, (
             "cannot make red boxes for the lltype Void")
         self.original_concretetype = original_concretetype
-        self.lowleveltype = timeshifter.r_RedBox.lowleveltype
-        self.timeshifter = timeshifter
+        self.lowleveltype = hrtyper.r_RedBox.lowleveltype
+        self.hrtyper = hrtyper
 
-    def get_genop_var(self, v, llops):
-        ts = self.timeshifter
-        v_jitstate = hop.llops.getjitstate()
-        return llops.genmixlevelhelpercall(rtimeshift.ll_gvar_from_redbox,
-                       [ts.s_JITState, llops.timeshifter.s_RedBox],
-                       [v_jitstate,    v],
-                       ts.s_ConstOrVar)
+##    def get_genop_var(self, v, llops):
+##        ts = self.hrtyper
+##        v_jitstate = hop.llops.getjitstate()
+##        return llops.genmixlevelhelpercall(rtimeshift.ll_gvar_from_redbox,
+##                       [ts.s_JITState, llops.hrtyper.s_RedBox],
+##                       [v_jitstate,    v],
+##                       ts.s_ConstOrVar)
 
     def convert_const(self, ll_value):
-        RGenOp = self.timeshifter.RGenOp
+        RGenOp = self.hrtyper.RGenOp
         redbox = rvalue.redbox_from_prebuilt_value(RGenOp, ll_value)
-        timeshifter = self.timeshifter
-        return timeshifter.annhelper.delayedconst(timeshifter.r_RedBox, redbox)
+        hrtyper = self.hrtyper
+        return hrtyper.annhelper.delayedconst(hrtyper.r_RedBox, redbox)
 
     def residual_values(self, ll_value):
         return [ll_value]
@@ -626,7 +966,7 @@
     typedesc = None
 
     def create(self, hop):
-        ts = self.timeshifter
+        ts = self.hrtyper
         if self.typedesc is None:
             T = self.original_concretetype.TO
             self.typedesc = rcontainer.StructTypeDesc(ts.RGenOp, T)
@@ -658,13 +998,13 @@
         else:
             return annmodel.SomeInteger()
 
-    def get_genop_var(self, v, llops):
-        ts = self.timeshifter
-        v_jitstate = hop.llops.getjitstate()
-        return llops.genmixlevelhelpercall(rtimeshift.ll_gvar_from_constant,
-                                           [ts.s_JITState, self.annotation()],
-                                           [v_jitstate,    v],
-                                           ts.s_ConstOrVar)
+##    def get_genop_var(self, v, llops):
+##        ts = self.hrtyper
+##        v_jitstate = hop.llops.getjitstate()
+##        return llops.genmixlevelhelpercall(rtimeshift.ll_gvar_from_constant,
+##                                           [ts.s_JITState, self.annotation()],
+##                                           [v_jitstate,    v],
+##                                           ts.s_ConstOrVar)
 
     def convert_const(self, ll_value):
         return ll_value
@@ -689,12 +1029,12 @@
 
     def convert_from_to((r_from, r_to), v, llops):
         assert r_from.lowleveltype == r_to.original_concretetype
-        ts = llops.timeshifter
+        ts = llops.hrtyper
         v_jitstate = llops.getjitstate()
         return llops.genmixlevelhelpercall(rvalue.ll_fromvalue,
                         [ts.s_JITState, r_from.annotation()],
                         [v_jitstate,    v],
-                        llops.timeshifter.s_RedBox)
+                        ts.s_RedBox)
 
 # ____________________________________________________________
 

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 21 11:30:27 2006
@@ -90,10 +90,9 @@
 
 def ll_fromvalue(jitstate, value):
     "Make a constant RedBox from a low-level value."
-    rgenop = jitstate.curbuilder.rgenop
+    gv = ll_gv_fromvalue(jitstate, value)
     T = lltype.typeOf(value)
-    kind = rgenop.kindToken(T)
-    gv = rgenop.genconst(value)
+    kind = jitstate.curbuilder.rgenop.kindToken(T)
     cls = ll_redboxcls(T)
     return cls(kind, gv)
 
@@ -104,10 +103,19 @@
     cls = ll_redboxcls(T)
     return cls(kind, gv)
 
+def ll_gv_fromvalue(jitstate, value):
+    rgenop = jitstate.curbuilder.rgenop
+    gv = rgenop.genconst(value)
+    return gv
+
 def ll_getvalue(box, T):
     "Return the content of a known-to-be-constant RedBox."
     return box.genvar.revealconst(T)
 
+def ll_is_constant(box):
+    "Check if a red box is known to be constant."
+    return box.is_constant()
+
 
 class IntRedBox(RedBox):
     "A red box that contains a constant integer-like value."

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 21 11:30:27 2006
@@ -3,7 +3,7 @@
 from pypy.jit.hintannotator.annotator import HintAnnotator
 from pypy.jit.hintannotator.bookkeeper import HintBookkeeper
 from pypy.jit.hintannotator.model import *
-from pypy.jit.timeshifter.timeshift import HintTimeshift
+from pypy.jit.timeshifter.rtyper import HintRTyper, originalconcretetype
 from pypy.jit.timeshifter import rtimeshift, rvalue, rtyper as hintrtyper
 from pypy.objspace.flow.model import summary
 from pypy.rpython.lltypesystem import lltype, llmemory, rstr
@@ -94,12 +94,13 @@
                                    backendoptimize=backendoptimize)
 
         # make the timeshifted graphs
-        htshift = HintTimeshift(ha, rtyper, self.RGenOp)
-        fresh_jitstate = htshift.ll_fresh_jitstate
-        finish_jitstate = htshift.ll_finish_jitstate
-        RESTYPE = htshift.originalconcretetype(
-            ha.translator.graphs[0].getreturnvar())
-        htshift.timeshift()
+        hrtyper = HintRTyper(ha, rtyper, self.RGenOp)
+        hrtyper.specialize(view = conftest.option.view)
+
+        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)
@@ -122,9 +123,9 @@
         argcolors = []
         generate_code_args_s = []
 
-        for v, llvalue in zip(graph1varargs, values):
+        for v, hs_arg, llvalue in zip(graph1varargs, args_hs, values):
             s_var = annmodel.ll_to_annotation(llvalue)
-            r = htshift.hrtyper.bindingrepr(v)
+            r = hrtyper.bindingrepr(v)
             residual_v = r.residual_values(llvalue)
             if len(residual_v) == 0:
                 color = "green"
@@ -132,9 +133,9 @@
             else:
                 color = "red"
                 assert residual_v == [llvalue], "XXX for now"
-                ARGTYPE = htshift.originalconcretetype(v)
+                ARGTYPE = originalconcretetype(hs_arg)
                 residual_argtypes.append(ARGTYPE)
-                timeshifted_entrypoint_args_s.append(htshift.s_RedBox)
+                timeshifted_entrypoint_args_s.append(hrtyper.s_RedBox)
                 generate_code_args_s.append(annmodel.SomeBool())
             argcolors.append(color)
             generate_code_args_s.append(s_var)
@@ -143,9 +144,9 @@
             graph1)
         timeshifted_entrypoint = PseudoHighLevelCallable(
             timeshifted_entrypoint_fnptr,
-            [htshift.s_JITState]
+            [hrtyper.s_JITState]
             + timeshifted_entrypoint_args_s,
-            htshift.s_JITState)
+            hrtyper.s_JITState)
         FUNC = lltype.FuncType(residual_argtypes, RESTYPE)
         argcolors = unrolling_iterable(argcolors)
         self.argcolors = argcolors
@@ -216,7 +217,7 @@
         self.ml_generate_code = ml_generate_code
 ##        self.ml_call_residual_graph = ml_call_residual_graph
         self.rtyper = rtyper
-        self.htshift = htshift
+        self.hrtyper = hrtyper
         self.annotate_interface_functions()
         if conftest.option.view:
             from pypy.translator.tool.graphpage import FlowGraphPage
@@ -228,7 +229,7 @@
         return values
 
     def annotate_interface_functions(self):
-        annhelper = self.htshift.annhelper
+        annhelper = self.hrtyper.annhelper
         RGenOp = self.RGenOp
         ml_generate_code = self.ml_generate_code
 ##        ml_call_residual_graph = self.ml_call_residual_graph
@@ -270,7 +271,7 @@
 
         # now try to run the residual graph generated by the builder
         residual_graph = ll_generated._obj.graph
-        residual_graph.exceptiontransformed = self.htshift.exc_data_ptr
+        residual_graph.exceptiontransformed = self.hrtyper.exc_data_ptr
         if conftest.option.view:
             residual_graph.show()
         self.insns = summary(residual_graph)
@@ -886,8 +887,19 @@
         res = self.timeshift(ll_function, [3], [], policy=P_NOVIRTUAL)
         assert res == 3
 
+    def test_green_call(self):
+        def ll_add_one(x):
+            return x+1
+        def ll_function(y):
+            z = ll_add_one(y)
+            z = hint(z, concrete=True)
+            return hint(z, variable=True)
+
+        res = self.timeshift(ll_function, [3], [0], policy=P_NOVIRTUAL)
+        assert res == 4
+        self.check_insns({})
+
     def test_split_on_green_return(self):
-        py.test.skip("in-progress")
         def ll_two(x):
             if x > 0:
                 return 17
@@ -895,7 +907,7 @@
                 return 22
         def ll_function(x):
             n = ll_two(x)
-            return n+1
+            return hint(n+1, variable=True)
         res = self.timeshift(ll_function, [-70], [])
         assert res == 23
         self.check_insns({'int_gt': 1})

Modified: pypy/dist/pypy/jit/timeshifter/vlist.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/vlist.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/vlist.py	Thu Sep 21 11:30:27 2006
@@ -8,7 +8,7 @@
 
     def __init__(self, hrtyper, LIST):
         RGenOp = hrtyper.RGenOp
-        rtyper = hrtyper.timeshifter.rtyper
+        rtyper = hrtyper.rtyper
         self.LIST = LIST
         self.LISTPTR = lltype.Ptr(LIST)
         self.ptrkind = RGenOp.kindToken(self.LISTPTR)

Modified: pypy/dist/pypy/rpython/rtyper.py
==============================================================================
--- pypy/dist/pypy/rpython/rtyper.py	(original)
+++ pypy/dist/pypy/rpython/rtyper.py	Thu Sep 21 11:30:27 2006
@@ -375,7 +375,7 @@
             self.insert_link_conversions(extrablock)
 
     def _convert_link(self, block, link):  
-        if link.exitcase is not None:
+        if link.exitcase is not None and link.exitcase != 'default':
             if isinstance(block.exitswitch, Variable):
                 r_case = self.bindingrepr(block.exitswitch)
             else:

Modified: pypy/dist/pypy/translator/backendopt/ssa.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/ssa.py	(original)
+++ pypy/dist/pypy/translator/backendopt/ssa.py	Thu Sep 21 11:30:27 2006
@@ -16,9 +16,7 @@
         # [Block, blockvar, linkvar, linkvar, linkvar...]
         opportunities = []
         opportunities_with_const = []
-        for block, links in mkentrymap(graph).items():
-            if block is graph.startblock:
-                continue
+        for block, links in mkinsideentrymap(graph).items():
             assert links
             for n, inputvar in enumerate(block.inputargs):
                 vars = [block, inputvar]
@@ -124,3 +122,95 @@
         vct = [getattr(v, 'concretetype', None) for v in vlist]
         assert vct == vct[:1] * len(vct), (
             "variables called %s have mixed concretetypes: %r" % (vname, vct))
+
+# ____________________________________________________________
+
+def mkinsideentrymap(graph_or_blocks):
+    # graph_or_blocks can be a full FunctionGraph, or a mapping
+    # {block: reachable-from-outside-flag}.
+    if isinstance(graph_or_blocks, dict):
+        blocks = graph_or_blocks
+        entrymap = {}
+        for block in blocks:
+            for link in block.exits:
+                if link.target in blocks and not blocks[link.target]:
+                    entrymap.setdefault(link.target, []).append(link)
+        return entrymap
+    else:
+        graph = graph_or_blocks
+        entrymap = mkentrymap(graph)
+        del entrymap[graph.startblock]
+        return entrymap
+
+def variables_created_in(block):
+    result = {}
+    for v in block.inputargs:
+        result[v] = True
+    for op in block.operations:
+        result[op.result] = True
+    return result
+
+
+def SSA_to_SSI(graph_or_blocks, annotator=None):
+    """Turn a number of blocks belonging to a flow graph into valid (i.e. SSI)
+    form, assuming that they are only in SSA form (i.e. they can use each
+    other's variables directly, without having to pass and rename them along
+    links).
+
+    'graph_or_blocks' can be a graph, or just a dict that lists some blocks
+    from a graph, as follows: {block: reachable-from-outside-flag}.
+    """
+    from pypy.translator.unsimplify import copyvar
+
+    entrymap = mkinsideentrymap(graph_or_blocks)
+    builder = DataFlowFamilyBuilder(graph_or_blocks)
+    variable_families = builder.get_variable_families()
+    del builder
+
+    pending = []     # list of (block, var-used-but-not-defined)
+
+    for block in entrymap:
+        variables_created = variables_created_in(block)
+        variables_used = {}
+        for op in block.operations:
+            for v in op.args:
+                if isinstance(v, Variable):
+                    variables_used[v] = True
+        if isinstance(block.exitswitch, Variable):
+            variables_used[v] = True
+        for link in block.exits:
+            for v in link.args:
+                if isinstance(v, Variable):
+                    variables_used[v] = True
+
+        for v in variables_used:
+            if v not in variables_created:
+                pending.append((block, v))
+
+    while pending:
+        block, v = pending.pop()
+        v_rep = variable_families.find_rep(v)
+        variables_created = variables_created_in(block)
+        if v in variables_created:
+            continue     # already ok
+        for w in variables_created:
+            w_rep = variable_families.find_rep(w)
+            if v_rep is w_rep:
+                # 'w' is in the same family as 'v', so we can simply
+                # reuse its value for 'v'
+                block.renamevariables({v: w})
+                break
+        else:
+            # didn't find it.  Add it to all incoming links.
+            try:
+                links = entrymap[block]
+            except KeyError:
+                raise Exception("SSA_to_SSI failed: no way to give a value to"
+                                " %r in %r" % (v, block))
+            w = copyvar(annotator, v)
+            variable_families.union(v, w)
+            block.renamevariables({v: w})
+            block.inputargs.append(w)
+            for link in links:
+                link.args.append(v)
+                pending.append((link.prevblock, v))

Modified: pypy/dist/pypy/translator/backendopt/test/test_ssa.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/test/test_ssa.py	(original)
+++ pypy/dist/pypy/translator/backendopt/test/test_ssa.py	Thu Sep 21 11:30:27 2006
@@ -1,6 +1,7 @@
 from pypy.translator.backendopt.ssa import *
 from pypy.translator.translator import TranslationContext
-from pypy.objspace.flow.model import flatten, Block
+from pypy.objspace.flow.model import flatten, Block, Link, Variable, Constant
+from pypy.objspace.flow.model import SpaceOperation
 
 
 def test_data_flow_families():
@@ -49,3 +50,63 @@
             allvars += [v.name for v in block.getvariables()]
     # see comments above for where the 8 remaining variables are expected to be
     assert len(dict.fromkeys(allvars)) == 8
+
+
+def test_SSA_to_SSI():
+    c = Variable('c')
+    x = Variable('x')
+    y = Variable('y')
+    b1 = Block([c])
+    b2 = Block([x])
+    b3 = Block([])
+
+    b2.operations.append(SpaceOperation('add', [x, c], y))
+    b2.exitswitch = y
+
+    b1.closeblock(Link([Constant(0)], b2))
+    b2.closeblock(Link([y], b2), Link([], b3))
+    b3.closeblock(Link([y, c], None))
+
+    SSA_to_SSI({b1: True,     # reachable from outside
+                b2: False,
+                b3: False})
+
+    assert len(b1.inputargs) == 1
+    assert len(b2.inputargs) == 2
+    assert len(b3.inputargs) == 2
+
+    assert b2.inputargs == b2.operations[0].args
+    assert len(b1.exits[0].args) == 2
+    assert b1.exits[0].args[1] is c
+    assert len(b2.exits[0].args) == 2
+    assert b2.exits[0].args == [y, b2.inputargs[1]]
+    assert len(b2.exits[1].args) == 2
+    assert len(b3.exits[0].args) == 2
+
+    index = b3.inputargs.index(b3.exits[0].args[0])
+    assert b2.exits[1].args[index] is b2.operations[0].result
+
+    index = b3.inputargs.index(b3.exits[0].args[1])
+    assert b2.exits[1].args[index] is b2.inputargs[1]
+
+
+def test_SSA_to_SSI_2():
+    x = Variable('x')
+    y = Variable('y')
+    z = Variable('z')
+    b1 = Block([x])
+    b2 = Block([y])
+    b3 = Block([])
+
+    b3.operations.append(SpaceOperation('hello', [y], z))
+    b1.closeblock(Link([x], b2), Link([], b3))
+
+    SSA_to_SSI({b1: True,     # reachable from outside
+                b2: False,
+                b3: False})
+
+    assert b1.inputargs == [x]
+    assert b2.inputargs == [y]
+    assert b3.inputargs == [b3.operations[0].args[0]]
+    assert b1.exits[0].args == [x]
+    assert b1.exits[1].args == [x]

Modified: pypy/dist/pypy/translator/simplify.py
==============================================================================
--- pypy/dist/pypy/translator/simplify.py	(original)
+++ pypy/dist/pypy/translator/simplify.py	Thu Sep 21 11:30:27 2006
@@ -63,10 +63,10 @@
                 if (len(link.target.exits) != 1 and
                     link.target.exitswitch != c_last_exception):
                     break
-                assert link.target is not link.prevblock, (
-                    "the graph contains an empty infinite loop")
                 block1 = link.target
                 exit = block1.exits[0]
+                assert block1 is not exit.target, (
+                    "the graph contains an empty infinite loop")
                 outputargs = []
                 for v in exit.args:
                     if isinstance(v, Variable):



More information about the Pypy-commit mailing list