[pypy-svn] r31972 - in pypy/dist/pypy/jit: codegen codegen/i386 codegen/i386/test codegen/llgraph timeshifter timeshifter/test

arigo at codespeak.net arigo at codespeak.net
Sun Sep 3 20:59:51 CEST 2006


Author: arigo
Date: Sun Sep  3 20:59:48 2006
New Revision: 31972

Modified:
   pypy/dist/pypy/jit/codegen/i386/ri386genop.py
   pypy/dist/pypy/jit/codegen/i386/test/test_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/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/timeshift.py
   pypy/dist/pypy/jit/timeshifter/vlist.py
Log:
(pedronis, arigo)

Big Diff Of The Day.  The rgenop interface is getting in a nice shape:
no more links, and no more geninputarg().  Back-end friendly.

ri386genop produces code that is a bit more reasonable now (e.g. it's no
longer 95% moves)...



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	Sun Sep  3 20:59:48 2006
@@ -1,7 +1,7 @@
 from pypy.rpython.objectmodel import specialize
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.jit.codegen.i386.ri386 import *
-from pypy.jit.codegen.model import AbstractRGenOp, CodeGenBlock, CodeGenLink
+from pypy.jit.codegen.model import AbstractRGenOp, CodeGenBlock, CodeGenerator
 from pypy.jit.codegen.model import GenVar, GenConst
 from pypy.rpython import objectmodel
 from pypy.rpython.annlowlevel import llhelper
@@ -12,19 +12,22 @@
 class Var(GenVar):
 
     def __init__(self, stackpos):
-        # 'stackpos' is an index relative to the pushed arguments:
-        #   0 = 1st arg,
-        #   1 = 2nd arg,
-        #       ...
-        #       return address,
-        #       local var,       ...
+        # 'stackpos' is an index relative to the pushed arguments
+        # (where N is the number of arguments of the function):
+        #
+        #  0  = last arg
+        #     = ...
+        # N-1 = 1st arg
+        #  N  = return address
+        # N+1 = local var
+        # N+2 = ...
         #       ...              <--- esp+4
         #       local var        <--- esp
         #
         self.stackpos = stackpos
 
-    def operand(self, block):
-        return block.stack_access(self.stackpos)
+    def operand(self, builder):
+        return builder.stack_access(self.stackpos)
 
     def __repr__(self):
         return 'var@%d' % (self.stackpos,)
@@ -60,7 +63,7 @@
     def __init__(self, value):
         self.value = value
 
-    def operand(self, block):
+    def operand(self, builder):
         return imm(self.value)
 
     @specialize.arg(1)
@@ -88,7 +91,7 @@
     def __init__(self, addr):
         self.addr = addr
 
-    def operand(self, block):
+    def operand(self, builder):
         return imm(llmemory.cast_adr_to_int(self.addr))
 
     @specialize.arg(1)
@@ -107,23 +110,31 @@
 
 
 class Block(CodeGenBlock):
-    def __init__(self, rgenop, mc):
+
+    def __init__(self, startaddr, arg_positions, stackdepth):
+        self.startaddr = startaddr
+        self.arg_positions = arg_positions
+        self.stackdepth = stackdepth
+
+
+class Builder(CodeGenerator):
+
+    def __init__(self, rgenop, mc, stackdepth):
         self.rgenop = rgenop
-        self.argcount = 0
-        self.stackdepth = 0
+        self.stackdepth = stackdepth
         self.mc = mc
-        self.startaddr = mc.tell()
-        self.fixedposition = False
 
-    def getstartaddr(self):
-        self.fixedposition = True
-        return self.startaddr
-
-    def geninputarg(self, kind):
-        res = Var(self.argcount)
-        self.argcount += 1
-        self.stackdepth += 1
-        return res
+    def _write_prologue(self, sigtoken):
+        numargs = sigtoken     # for now
+        #self.mc.BREAKPOINT()
+        return [Var(pos) for pos in range(numargs-1, -1, -1)]
+
+    def _close(self):
+        self.rgenop.close_mc(self.mc)
+        self.mc = None
+
+    def _fork(self):
+        return self.rgenop.openbuilder(self.stackdepth)
 
     @specialize.arg(1)
     def genop1(self, opname, gv_arg):
@@ -194,16 +205,44 @@
         else:
             return gv_x
 
-    def close1(self):
-        return Link(self)
+    def enter_next_block(self, kinds, args_gv):
+        arg_positions = []
+        seen = {}
+        for i in range(len(args_gv)):
+            gv = args_gv[i]
+            # turn constants into variables; also make copies of vars that
+            # are duplicate in args_gv
+            if not isinstance(gv, Var) or gv.stackpos in seen:
+                gv = args_gv[i] = self.returnvar(gv.operand(self))
+            # remember the var's position in the stack
+            arg_positions.append(gv.stackpos)
+            seen[gv.stackpos] = None
+        return Block(self.mc.tell(), arg_positions, self.stackdepth)
+
+    def jump_if_false(self, gv_condition):
+        targetbuilder = self._fork()
+        self.mc.CMP(gv_condition.operand(self), imm8(0))
+        self.mc.JE(rel32(targetbuilder.mc.tell()))
+        return targetbuilder
 
-    def close2(self, gv_condition):
-        false_block = self.rgenop.newblock()
-        false_block.stackdepth = self.stackdepth
-        # XXX what if gv_condition is a Const?
+    def jump_if_true(self, gv_condition):
+        targetbuilder = self._fork()
         self.mc.CMP(gv_condition.operand(self), imm8(0))
-        self.mc.JE(rel32(false_block.getstartaddr()))
-        return Link(false_block), Link(self)
+        self.mc.JNE(rel32(targetbuilder.mc.tell()))
+        return targetbuilder
+
+    def finish_and_return(self, sigtoken, gv_returnvar):
+        numargs = sigtoken      # for now
+        initialstackdepth = numargs + 1
+        self.mc.MOV(eax, gv_returnvar.operand(self))
+        self.mc.ADD(esp, imm(WORD * (self.stackdepth - initialstackdepth)))
+        self.mc.RET()
+        self._close()
+
+    def finish_and_goto(self, outputargs_gv, targetblock):
+        remap_stack_layout(self, outputargs_gv, targetblock)
+        self.mc.JMP(rel32(targetblock.startaddr))
+        self._close()
 
     # ____________________________________________________________
 
@@ -357,78 +396,74 @@
 
 # ____________________________________________________________
 
-class Link(CodeGenLink):
-
-    def __init__(self, prevblock):
-        self.prevblock = prevblock
-
-    def closereturn(self, gv_result):
-        block = self.prevblock
-        block.mc.MOV(eax, gv_result.operand(block))
-        block.mc.ADD(esp, imm(WORD * block.stackdepth))
-        block.mc.RET()
-        block.rgenop.close_mc(block.mc)
-
-    def close(self, outputargs_gv, targetblock):
-        block = self.prevblock
-        N = len(outputargs_gv)
-        if block.stackdepth < N:
-            block.mc.SUB(esp, imm(WORD * (N - block.stackdepth)))
-            block.stackdepth = N
+def remap_stack_layout(builder, outputargs_gv, targetblock):
+    N = targetblock.stackdepth
+    if builder.stackdepth < N:
+        builder.mc.SUB(esp, imm(WORD * (N - builder.stackdepth)))
+        builder.stackdepth = N
+
+    M = len(outputargs_gv)
+    arg_positions = targetblock.arg_positions
+    assert M == len(arg_positions)
+    targetlayout = [None] * N
+    srccount = [-N] * N
+    for i in range(M):
+        pos = arg_positions[i]
+        gv = outputargs_gv[i]
+        assert targetlayout[pos] is None
+        targetlayout[pos] = gv
+        srccount[pos] = 0
+    pending_dests = M
+    for i in range(M):
+        gv = outputargs_gv[i]
+        if isinstance(gv, Var):
+            p = gv.stackpos
+            if 0 <= p < N:
+                if p == i:
+                    srccount[p] = -N     # ignore 'v=v'
+                    pending_dests -= 1
+                else:
+                    srccount[p] += 1
 
-        pending_dests = N
-        srccount = [0] * N
+    while pending_dests:
+        progress = False
         for i in range(N):
-            gv = outputargs_gv[i]
-            if isinstance(gv, Var):
-                p = gv.stackpos
-                if 0 <= p < N:
-                    if p == i:
-                        srccount[p] = -N     # ignore 'v=v'
-                        pending_dests -= 1
-                    else:
-                        srccount[p] += 1
-
-        while pending_dests:
-            progress = False
+            if srccount[i] == 0:
+                srccount[i] = -1
+                pending_dests -= 1
+                gv_src = targetlayout[i]
+                if isinstance(gv_src, Var):
+                    p = gv_src.stackpos
+                    if 0 <= p < N:
+                        srccount[p] -= 1
+                builder.mc.MOV(eax, gv_src.operand(builder))
+                builder.mc.MOV(builder.stack_access(i), eax)
+                progress = True
+        if not progress:
+            # we are left with only pure disjoint cycles; break them
             for i in range(N):
-                if srccount[i] == 0:
-                    srccount[i] = -1
-                    pending_dests -= 1
-                    gv_src = outputargs_gv[i]
-                    if isinstance(gv_src, Var):
-                        p = gv_src.stackpos
-                        if 0 <= p < N:
-                            srccount[p] -= 1
-                    block.mc.MOV(eax, gv_src.operand(block))
-                    block.mc.MOV(block.stack_access(i), eax)
-                    progress = True
-            if not progress:
-                # we are left with only pure disjoint cycles; break them
-                for i in range(N):
-                    if srccount[i] >= 0:
-                        dst = i
-                        block.mc.MOV(edx, block.stack_access(dst))
-                        while True:
-                            assert srccount[dst] == 1
-                            srccount[dst] = -1
-                            pending_dests -= 1
-                            gv_src = outputargs_gv[dst]
-                            assert isinstance(gv_src, Var)
-                            src = gv_src.stackpos
-                            assert 0 <= src < N
-                            if src == i:
-                                break
-                            block.mc.MOV(eax, block.stack_access(src))
-                            block.mc.MOV(block.stack_access(dst), eax)
-                            dst = src
-                        block.mc.MOV(block.stack_access(dst), edx)
-                assert pending_dests == 0
-
-        if block.stackdepth > N:
-            block.mc.ADD(esp, imm(WORD * (block.stackdepth - N)))
-            block.stackdepth = N
-        block.rgenop.close_mc_and_jump(block.mc, targetblock)
+                if srccount[i] >= 0:
+                    dst = i
+                    builder.mc.MOV(edx, builder.stack_access(dst))
+                    while True:
+                        assert srccount[dst] == 1
+                        srccount[dst] = -1
+                        pending_dests -= 1
+                        gv_src = targetlayout[dst]
+                        assert isinstance(gv_src, Var)
+                        src = gv_src.stackpos
+                        assert 0 <= src < N
+                        if src == i:
+                            break
+                        builder.mc.MOV(eax, builder.stack_access(src))
+                        builder.mc.MOV(builder.stack_access(dst), eax)
+                        dst = src
+                    builder.mc.MOV(builder.stack_access(dst), edx)
+            assert pending_dests == 0
+
+    if builder.stackdepth > N:
+        builder.mc.ADD(esp, imm(WORD * (builder.stackdepth - N)))
+        builder.stackdepth = N
 
 
 class RI386GenOp(AbstractRGenOp):
@@ -447,20 +482,16 @@
     def close_mc(self, mc):
         self.mcs.append(mc)
 
-    def close_mc_and_jump(self, mc, targetblock):
-        if (targetblock.fixedposition
-            or targetblock.mc.tell() != targetblock.startaddr):
-            mc.JMP(rel32(targetblock.getstartaddr()))
-            self.close_mc(mc)
-        else:
-            # bring the targetblock here, instead of jumping to it
-            self.close_mc(targetblock.mc)
-            targetblock.mc = mc
-            targetblock.startaddr = mc.tell()
-            targetblock.fixedposition = True
+    def openbuilder(self, stackdepth):
+        return Builder(self, self.open_mc(), stackdepth)
 
-    def newblock(self):
-        return Block(self, self.open_mc())
+    def newgraph(self, sigtoken):
+        numargs = sigtoken          # for now
+        initialstackdepth = numargs+1
+        builder = self.openbuilder(initialstackdepth)
+        entrypoint = builder.mc.tell()
+        inputargs_gv = builder._write_prologue(sigtoken)
+        return builder, entrypoint, inputargs_gv
 
     @staticmethod
     @specialize.genconst(0)
@@ -500,18 +531,10 @@
     @staticmethod
     @specialize.memo()
     def sigToken(FUNCTYPE):
-        return None     # for now
+        return len(FUNCTYPE.ARGS)     # for now
 
     constPrebuiltGlobal = genconst
 
 
-    def gencallableconst(self, sigtoken, name, block):
-        prologue = self.newblock()
-        #prologue.mc.BREAKPOINT()
-        # re-push the arguments so that they are after the return value
-        # and in the correct order
-        for i in range(block.argcount):
-            operand = mem(esp, WORD * (2*i+1))
-            prologue.mc.PUSH(operand)
-        self.close_mc_and_jump(prologue.mc, block)
-        return IntConst(prologue.getstartaddr())
+    def gencallableconst(self, sigtoken, name, entrypointaddr):
+        return IntConst(entrypointaddr)

Modified: pypy/dist/pypy/jit/codegen/i386/test/test_ri386genop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/test/test_ri386genop.py	(original)
+++ pypy/dist/pypy/jit/codegen/i386/test/test_ri386genop.py	Sun Sep  3 20:59:48 2006
@@ -15,15 +15,11 @@
 
 def make_adder(rgenop, n):
     # 'return x+n'
-    signed_kind = rgenop.kindToken(lltype.Signed)
-    block = rgenop.newblock()
-    gv_x = block.geninputarg(signed_kind)
-    gv_result = block.genop2("int_add", gv_x, rgenop.genconst(n))
-    link = block.close1()
-    link.closereturn(gv_result)
-
     sigtoken = rgenop.sigToken(FUNC)
-    gv_add_one = rgenop.gencallableconst(sigtoken, "adder", block)
+    builder, entrypoint, [gv_x] = rgenop.newgraph(sigtoken)
+    gv_result = builder.genop2("int_add", gv_x, rgenop.genconst(n))
+    builder.finish_and_return(sigtoken, gv_result)
+    gv_add_one = rgenop.gencallableconst(sigtoken, "adder", entrypoint)
     return gv_add_one
 
 def runner(x, y):
@@ -62,25 +58,19 @@
 def make_dummy(rgenop):
     # 'return x - (y - (x-1))'
     signed_kind = rgenop.kindToken(lltype.Signed)
-    block = rgenop.newblock()
-    gv_x = block.geninputarg(signed_kind)
-    gv_y = block.geninputarg(signed_kind)
-    gv_z = block.genop2("int_sub", gv_x, rgenop.genconst(1))
-    link = block.close1()
-
-    block2 = rgenop.newblock()
-    gv_y2 = block2.geninputarg(signed_kind)
-    gv_z2 = block2.geninputarg(signed_kind)
-    gv_x2 = block2.geninputarg(signed_kind)
-    link.close([gv_y, gv_z, gv_x], block2)
-
-    gv_s2 = block2.genop2("int_sub", gv_y2, gv_z2)
-    gv_t2 = block2.genop2("int_sub", gv_x2, gv_s2)
-    link2 = block2.close1()
-
-    link2.closereturn(gv_t2)
     sigtoken = rgenop.sigToken(FUNC2)
-    gv_dummyfn = rgenop.gencallableconst(sigtoken, "dummy", block)
+    builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken)
+    gv_z = builder.genop2("int_sub", gv_x, rgenop.genconst(1))
+
+    args_gv = [gv_y, gv_z, gv_x]
+    builder.enter_next_block([signed_kind, signed_kind, signed_kind], args_gv)
+    [gv_y2, gv_z2, gv_x2] = args_gv
+
+    gv_s2 = builder.genop2("int_sub", gv_y2, gv_z2)
+    gv_t2 = builder.genop2("int_sub", gv_x2, gv_s2)
+    builder.finish_and_return(sigtoken, gv_t2)
+
+    gv_dummyfn = rgenop.gencallableconst(sigtoken, "dummy", entrypoint)
     return gv_dummyfn
 
 def dummy_runner(x, y):
@@ -118,27 +108,25 @@
     # 'if x > 5: return x-1
     #  else:     return y'
     signed_kind = rgenop.kindToken(lltype.Signed)
-    block = rgenop.newblock()
-    gv_x = block.geninputarg(signed_kind)
-    gv_y = block.geninputarg(signed_kind)
-    gv_cond = block.genop2("int_gt", gv_x, rgenop.genconst(5))
-    link_false, link_true = block.close2(gv_cond)
-
-    block2 = rgenop.newblock()
-    gv_one = block2.geninputarg(signed_kind)
-    gv_x2 = block2.geninputarg(signed_kind)
-    gv_y2 = block2.geninputarg(signed_kind)
-    link_true.close([rgenop.genconst(1), gv_x, gv_y], block2)
-
-    gv_s2 = block2.genop2("int_sub", gv_x2, gv_one)
-    link2 = block2.close1()
-    link2.closereturn(gv_s2)
+    sigtoken = rgenop.sigToken(FUNC2)
+    builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken)
+    gv_cond = builder.genop2("int_gt", gv_x, rgenop.genconst(5))
+    false_builder = builder.jump_if_false(gv_cond)
+
+    # true path
+    args_gv = [rgenop.genconst(1), gv_x, gv_y]
+    builder.enter_next_block([signed_kind, signed_kind, signed_kind], args_gv)
+    [gv_one, gv_x2, gv_y2] = args_gv
 
-    link_false.closereturn(gv_y)
+    gv_s2 = builder.genop2("int_sub", gv_x2, gv_one)
+    builder.finish_and_return(sigtoken, gv_s2)
 
-    sigtoken = rgenop.sigToken(FUNC2)
+    # false path
+    false_builder.finish_and_return(sigtoken, gv_y)
+
+    # done
     gv_branchingfn = rgenop.gencallableconst(sigtoken,
-                                             "branching", block)
+                                             "branching", entrypoint)
     return gv_branchingfn
 
 def branching_runner(x, y):
@@ -175,3 +163,71 @@
     assert res == 29
     res = fn(3, 17)
     assert res == 17
+
+# ____________________________________________________________
+
+def make_goto(rgenop):
+    # while x > 0:
+    #     y += x
+    #     x -= 1
+    # return y
+    signed_kind = rgenop.kindToken(lltype.Signed)
+    sigtoken = rgenop.sigToken(FUNC2)
+    builder, entrypoint, [gv_x, gv_y] = rgenop.newgraph(sigtoken)
+
+    # loop start block
+    args_gv = [gv_x, gv_y]
+    loopblock = builder.enter_next_block([signed_kind, signed_kind], args_gv)
+    [gv_x, gv_y] = args_gv
+
+    gv_cond = builder.genop2("int_gt", gv_x, rgenop.genconst(0))
+    bodybuilder = builder.jump_if_true(gv_cond)
+    builder.finish_and_return(sigtoken, gv_y)
+
+    # loop body
+    args_gv = [gv_y, gv_x]
+    bodybuilder.enter_next_block([signed_kind, signed_kind], args_gv)
+    [gv_y, gv_x] = args_gv
+
+    gv_y2 = bodybuilder.genop2("int_add", gv_x, gv_y)
+    gv_x2 = bodybuilder.genop2("int_sub", gv_x, rgenop.genconst(1))
+    bodybuilder.finish_and_goto([gv_x2, gv_y2], loopblock)
+
+    # done
+    gv_gotofn = rgenop.gencallableconst(sigtoken, "goto", entrypoint)
+    return gv_gotofn
+
+def goto_runner(x, y):
+    rgenop = RI386GenOp()
+    gv_gotofn = make_goto(rgenop)
+    gotofn = gv_gotofn.revealconst(lltype.Ptr(FUNC2))
+    res = gotofn(x, y)
+    keepalive_until_here(rgenop)    # to keep the code blocks alive
+    return res
+
+def test_goto_interpret():
+    from pypy.jit.codegen.llgraph.rgenop import rgenop
+    gv_gotofn = make_goto(rgenop)
+    gotofn = gv_gotofn.revealconst(lltype.Ptr(FUNC2))
+    llinterp = LLInterpreter(None)
+    res = llinterp.eval_graph(gotofn._obj.graph, [30, 17])
+    assert res == 31 * 15 + 17
+    res = llinterp.eval_graph(gotofn._obj.graph, [3, 17])
+    assert res == 23
+
+def test_goto_direct():
+    rgenop = RI386GenOp()
+    gv_gotofn = make_goto(rgenop)
+    print gv_gotofn.value
+    fnptr = cast(c_void_p(gv_gotofn.value), CFUNCTYPE(c_int, c_int, c_int))
+    res = fnptr(30, 17)    # <== the segfault is here
+    assert res == 31 * 15 + 17
+    res = fnptr(3, 17)    # <== or here
+    assert res == 23
+
+def test_goto_compile():
+    fn = compile(goto_runner, [int, int], annotatorpolicy=GENOP_POLICY)
+    res = fn(30, 17)
+    assert res == 31 * 15 + 17
+    res = fn(3, 17)
+    assert res == 23

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	Sun Sep  3 20:59:48 2006
@@ -215,6 +215,7 @@
 
 def _closelink(link, vars, targetblock):
     if isinstance(link, flowmodel.Link):
+        assert link.target is None     # link already closed
         blockvars = dict.fromkeys(link.prevblock.getvariables())
         for v in vars:
             if isinstance(v, flowmodel.Variable):

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	Sun Sep  3 20:59:48 2006
@@ -1,6 +1,6 @@
 from pypy.rpython.objectmodel import specialize
 from pypy.rpython.lltypesystem import lltype
-from pypy.jit.codegen.model import AbstractRGenOp, CodeGenBlock, CodeGenLink
+from pypy.jit.codegen.model import AbstractRGenOp, CodeGenBlock, CodeGenerator
 from pypy.jit.codegen.model import GenVar, GenConst
 from pypy.jit.codegen.llgraph import llimpl
 from pypy.rpython.lltypesystem.rclass import fishllattr
@@ -33,13 +33,11 @@
     def __init__(self, b):
         self.b = b
 
-    def geninputarg(self, gv_TYPE):
-        return LLVar(llimpl.geninputarg(self.b, gv_TYPE.v))
+class LLBuilder(CodeGenerator):
+    lnk = llimpl.nulllink
 
-##    @specialize.arg(1)
-##    def genop(self, opname, vars_gv, gv_RESULT_TYPE=None):
-##        return LLVar(llimpl.genop(self.b, opname, vars_gv,
-##                                  (gv_RESULT_TYPE or gv_Void).v))
+    def __init__(self):
+        self.rgenop = rgenop
 
     @specialize.arg(1)
     def genop1(self, opname, gv_arg):
@@ -100,36 +98,59 @@
     def genop_same_as(self, gv_TYPE, gv_value):
         return LLVar(gv_value.v)
 
-    def close1(self):
-        return LLLink(llimpl.closeblock1(self.b))
-
-    def close2(self, gv_exitswitch):
-        l1, l2 = llimpl.closeblock2(self.b, gv_exitswitch.v)
-        return LLLink(l1), LLLink(l2)
-
-
-class LLLink(CodeGenLink):
-    def __init__(self, l):
-        self.l = l
-
-    def close(self, vars_gv, targetblock):
-        llimpl.closelink(self.l, vars_gv, targetblock.b)
-
-    def closereturn(self, gv_returnvar):
-        llimpl.closereturnlink(self.l,
+    def _newblock(self, kinds):
+        self.b = newb = llimpl.newblock()
+        return [LLVar(llimpl.geninputarg(newb, kind.v)) for kind in kinds]
+
+    def enter_next_block(self, kinds, args_gv):
+        lnk = self.lnk or llimpl.closeblock1(self.b)
+        self.lnk = llimpl.nulllink
+        newb_args_gv = self._newblock(kinds) 
+        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)
+
+    def finish_and_goto(self, args_gv, targetblock):
+        lnk = self.lnk or llimpl.closeblock1(self.b)
+        self.lnk = llimpl.nulllink
+        llimpl.closelink(lnk, args_gv, targetblock.b)
+
+    def finish_and_return(self, sigtoken, gv_returnvar):
+        lnk = self.lnk or llimpl.closeblock1(self.b)
+        self.lnk = llimpl.nulllink
+        llimpl.closereturnlink(lnk,
                                (gv_returnvar or gv_dummy_placeholder).v)
 
+    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.lnk = l_true
+        self.lnk = l_false
+        return later_builder
+
+    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.lnk = l_false
+        self.lnk = l_true
+        return later_builder
+
 
 class RGenOp(AbstractRGenOp):
     gv_Void = gv_Void
 
-    def newblock(self):
-        return LLBlock(llimpl.newblock())
 
-    # XXX what kind of type/kind information does this need?
+    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,
-                         targetblock):
-        return LLConst(llimpl.gencallableconst(name, targetblock.b,
+                         entrypoint):
+        return LLConst(llimpl.gencallableconst(name, entrypoint.b,
                                                gv_FUNCTYPE.v))
 
     @staticmethod

Modified: pypy/dist/pypy/jit/codegen/model.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/model.py	(original)
+++ pypy/dist/pypy/jit/codegen/model.py	Sun Sep  3 20:59:48 2006
@@ -10,10 +10,10 @@
     is_const = True
 
 
-class CodeGenBlock(object):
+class CodeGenerator(object):
     pass
 
-class CodeGenLink(object):
+class CodeGenBlock(object):
     pass
 
 

Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rcontainer.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rcontainer.py	Sun Sep  3 20:59:48 2006
@@ -170,12 +170,12 @@
                               for desc in typedesc.fielddescs]
         #self.ownbox = ... set in ll_factory()
 
-    def enter_block(self, newblock, incoming, memo):
+    def enter_block(self, incoming, memo):
         contmemo = memo.containers
         if self not in contmemo:
             contmemo[self] = None
             for box in self.content_boxes:
-                box.enter_block(newblock, incoming, memo)
+                box.enter_block(incoming, memo)
 
     def force_runtime_container(self, builder):
         typedesc = self.typedesc

Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtimeshift.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py	Sun Sep  3 20:59:48 2006
@@ -139,11 +139,10 @@
 # ____________________________________________________________
 # other jitstate/graph level operations
 
-def enter_graph(builder, backstate=None):
-    return builder.build_jitstate(backstate)
+def enter_graph(backstate):
+    return JITState(backstate.curbuilder, backstate)
 
 def start_new_block(states_dic, jitstate, key, redboxes):
-    rgenop = jitstate.rgenop
     memo = rvalue.freeze_memo()
     frozens = [redbox.freeze(memo) for redbox in redboxes]
     memo = rvalue.exactmatch_memo()
@@ -151,13 +150,16 @@
     for i in range(len(redboxes)):
         res = frozens[i].exactmatch(redboxes[i], outgoingvarboxes, memo)
         assert res, "exactmatch() failed"
-    newblock = rgenop.newblock()
     linkargs = []
-    for box in outgoingvarboxes:
-        linkargs.append(box.getgenvar(None))
-        box.genvar = newblock.geninputarg(box.kind)
-    jitstate.curbuilder.enter_block(linkargs, newblock)
+    kinds = []
+    for box in outgoingvarboxes: # all variables
+        linkargs.append(box.genvar)
+        kinds.append(box.kind)
+    newblock = jitstate.curbuilder.enter_next_block(kinds, linkargs)
     states_dic[key] = frozens, newblock
+    for i in range(len(outgoingvarboxes)):
+        box = outgoingvarboxes[i]
+        box.genvar = linkargs[i]
     return jitstate
 start_new_block._annspecialcase_ = "specialize:arglltype(2)"
 
@@ -178,18 +180,15 @@
             exactmatch = False
 
     if exactmatch:
-        jitstate = dyn_enter_block(jitstate, outgoingvarboxes)
         linkargs = []
         for box in outgoingvarboxes:
             linkargs.append(box.getgenvar(jitstate.curbuilder))
-        jitstate.curbuilder.leave_block()
         jitstate.curbuilder.finish_and_goto(linkargs, oldblock)
         return None
 
     # We need a more general block.  Do it by generalizing all the
     # redboxes from outgoingvarboxes, by making them variables.
     # Then we make a new block based on this new state.
-    jitstate = dyn_enter_block(jitstate, outgoingvarboxes)
     replace_memo = rvalue.copy_memo()
     for box in outgoingvarboxes:
         box = box.forcevar(jitstate.curbuilder, replace_memo)
@@ -197,54 +196,45 @@
         for i in range(len(mylocalredboxes)):
             newbox = redboxes[i].replace(replace_memo)
             mylocalredboxes[i] = redboxes[i] = newbox
-    jitstate.curbuilder.leave_block()
     return start_new_block(states_dic, jitstate, key, redboxes)
 retrieve_jitstate_for_merge._annspecialcase_ = "specialize:arglltype(2)"
     
 def enter_block(jitstate, redboxes):
     # 'redboxes' is a fixed-size list (s_box_list) of the current red boxes
-    rgenop = jitstate.rgenop
-    newblock = rgenop.newblock()
-    incoming = []
-    memo = rvalue.enter_block_memo()
-    for redbox in redboxes:
-        redbox.enter_block(newblock, incoming, memo)
-    js = jitstate.backstate
-    while js is not None:
-        lrb = js.localredboxes
-        assert lrb is not None
-        for redbox in lrb:
-            redbox.enter_block(newblock, incoming, memo)
-        js = js.backstate
-    jitstate.curbuilder.enter_block(incoming, newblock)
-    return jitstate
-
-def dyn_enter_block(jitstate, redboxes):
-    # 'redboxes' is a var-sized list (s_box_accum) of *all* the boxes
-    # including the ones from the callers' locals
-    rgenop = jitstate.rgenop
-    newblock = rgenop.newblock()
     incoming = []
     memo = rvalue.enter_block_memo()
     for redbox in redboxes:
-        redbox.enter_block(newblock, incoming, memo)
-    jitstate.curbuilder.enter_block(incoming, newblock)
-    return jitstate
-
-def leave_block(jitstate):
-    jitstate.curbuilder.leave_block()
-    return jitstate
+        redbox.enter_block(incoming, memo)
+##    XXX
+##    js = jitstate.backstate
+##    while js is not None:
+##        lrb = js.localredboxes
+##        assert lrb is not None
+##        for redbox in lrb:
+##            redbox.enter_block(incoming, memo)
+##        js = js.backstate
+    linkargs = []
+    kinds = []
+    for redbox in incoming: # all variables
+        linkargs.append(redbox.genvar)
+        kinds.append(redbox.kind)
+    jitstate.curbuilder.enter_next_block(kinds, linkargs)
+    for i in range(len(incoming)):
+        incoming[i].genvar = linkargs[i]
 
-def leave_block_split(jitstate, switchredbox, exitindex, redboxes):
+def leave_block_split(jitstate, switchredbox, exitindex,
+                      redboxes_true, redboxes_false):
     if switchredbox.is_constant():
-        jitstate.curbuilder.leave_block()
         return rvalue.ll_getvalue(switchredbox, lltype.Bool)
     else:
         exitgvar = switchredbox.getgenvar(jitstate.curbuilder)
-        later_builder = jitstate.curbuilder.leave_block_split(exitgvar)
+        later_builder = jitstate.curbuilder.jump_if_false(exitgvar)
         memo = rvalue.copy_memo()
-        redboxcopies = [redbox.copy(memo) for redbox in redboxes]        
+        redboxcopies = [None] * len(redboxes_false)
+        for i in range(len(redboxes_false)):
+            redboxcopies[i] = redboxes_false[i].copy(memo)
         jitstate.split_queue.append((exitindex, later_builder, redboxcopies))
+        enter_block(jitstate, redboxes_true)
         return True
 
 def dispatch_next(jitstate, outredboxes):
@@ -252,6 +242,7 @@
     if split_queue:
         exitindex, later_builder, redboxes = split_queue.pop()
         jitstate.curbuilder = later_builder
+        enter_block(jitstate, redboxes)
         for box in redboxes:
             outredboxes.append(box)
         return exitindex
@@ -263,15 +254,13 @@
     
 def prepare_return(jitstate, cache, return_type):
     for builder, retbox in jitstate.return_queue[:-1]:
-        builder.leave_block()
         jitstate.curbuilder = builder
-        retrieve_jitstate_for_merge(cache, jitstate, (), [retbox])
+        res = retrieve_jitstate_for_merge(cache, jitstate, (), [retbox])
+        assert res is None
     frozens, block = cache[()]
-    _, returnbox = jitstate.return_queue[-1]
-    rgenop = jitstate.rgenop
-    builder = ResidualGraphBuilder(rgenop, block)
-    builder.valuebox = returnbox
-    return builder
+    builder, returnbox = jitstate.return_queue[-1]
+    jitstate.backstate.curbuilder = builder 
+    return returnbox
 
 def ll_gvar_from_redbox(jitstate, redbox):
     return redbox.getgenvar(jitstate.curbuilder)
@@ -282,125 +271,11 @@
 def save_locals(jitstate, redboxes):
     jitstate.localredboxes = redboxes
 
-def before_call(jitstate):
-    leave_block(jitstate)
-    return jitstate.curbuilder
-
-def after_call(jitstate, newbuilder):
-    jitstate.curbuilder = newbuilder
-    return newbuilder.valuebox
-
 # ____________________________________________________________
 
-class ResidualGraphBuilder(object):
-    def __init__(self, rgenop, block=None, link=None):
-        self.rgenop = rgenop
-        self.block = block
-        self.outgoinglink = link
-        self.valuebox = None
-
-    def genconst(self, llvalue):
-        return self.rgenop.genconst(llvalue)
-    genconst._annspecialcase_ = 'specialize:genconst(1)'
-
-##    def genvoidconst(self, dummy):
-##        return self.rgenop.placeholder(dummy)
-##    genvoidconst._annspecialcase_ = 'specialize:arg(1)'
-
-##    def genop(self, opname, args_gv, result_kind=None):
-##        return self.block.genop(opname, args_gv, result_kind)
-##    genop._annspecialcase_ = 'specialize:arg(1)'
-
-    def genop1(self, opname, gv_arg):
-        return self.block.genop1(opname, gv_arg)
-    genop1._annspecialcase_ = 'specialize:arg(1)'
-
-    def genop2(self, opname, gv_arg1, gv_arg2):
-        return self.block.genop2(opname, gv_arg1, gv_arg2)
-    genop2._annspecialcase_ = 'specialize:arg(1)'
-
-    def genop_call(self, sigtoken, gv_callable, args_gv):
-        return self.block.genop_call(sigtoken, gv_callable, args_gv)
-
-    def genop_getfield(self, fieldtoken, gv_ptr):
-        return self.block.genop_getfield(fieldtoken, gv_ptr)
-
-    def genop_setfield(self, fieldtoken, gv_ptr, gv_value):
-        return self.block.genop_setfield(fieldtoken, gv_ptr, gv_value)
-
-    def genop_getsubstruct(self, fieldtoken, gv_ptr):
-        return self.block.genop_getsubstruct(fieldtoken, gv_ptr)
-
-    def genop_getarrayitem(self, arraytoken, gv_ptr, gv_index):
-        return self.block.genop_getarrayitem(arraytoken, gv_ptr, gv_index)
-    
-    def genop_getarraysize(self, arraytoken, gv_ptr):
-        return self.block.genop_getarraysize(arraytoken, gv_ptr)
-
-    def genop_malloc_fixedsize(self, alloctoken):
-        return self.block.genop_malloc_fixedsize(alloctoken)
-
-    def genop_same_as(self, kind, gv_value):
-        return self.block.genop_same_as(kind, gv_value)
-
-    def constTYPE(self, T):
-        return self.rgenop.constTYPE(T)
-    constTYPE._annspecialcase_ = 'specialize:arg(1)'
-
-    def build_jitstate(self, backstate=None):
-        return JITState(self, backstate)
-
-    def enter_block(self, linkargs, newblock):
-        self.outgoinglink.close(linkargs, newblock)
-        self.block = newblock
-        self.outgoinglink = None
-   
-    def leave_block(self):
-        self.outgoinglink = self.block.close1()
-
-    def leave_block_split(self, exitgvar):
-        false_link, true_link = self.block.close2(exitgvar)    
-        later_builder = ResidualGraphBuilder(self.rgenop, link=false_link)
-        self.outgoinglink = true_link
-        return later_builder
-
-    def finish_and_goto(self, linkargs, targetblock):
-        self.outgoinglink.close(linkargs, targetblock)
-        self.outgoinglink = None
-        
-    def finish_and_return(self):
-        gv_retval = self.valuebox.getgenvar(self)
-        returnlink = self.block.close1()
-        returnlink.closereturn(gv_retval)
-
-def make_builder(rgenop):
-    return ResidualGraphBuilder(rgenop, rgenop.newblock())
-
-def ll_int_box(kind, gv):
-    return rvalue.IntRedBox(kind, gv)
-
-def ll_double_box(kind, gv):
-    return rvalue.DoubleRedBox(kind, gv)
-
-def ll_addr_box(kind, gv):
-    return rvalue.PtrRedBox(kind, gv)
-
-def ll_geninputarg(builder, kind):
-    return builder.block.geninputarg(kind)
-
-def ll_end_setup_builder(builder):
-    builder.leave_block()
-    return builder.block
-    
-def ll_close_builder(builder):
-    builder.finish_and_return()
-
-def ll_gencallableconst(builder, name, startblock, gv_functype):
-    return builder.rgenop.gencallableconst(name, startblock, gv_functype)
-
 class JITState(object):
     # XXX obscure interface
-    localredboxes = None
+    localredboxes = []
 
     def __init__(self, builder, backstate=None):
         self.split_queue = []

Modified: pypy/dist/pypy/jit/timeshifter/rtyper.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtyper.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rtyper.py	Sun Sep  3 20:59:48 2006
@@ -242,34 +242,24 @@
             return v
         else:
             bk = self.annotator.bookkeeper
-            # first close the current block
             ts = self.timeshifter
             v_jitstate = hop.llops.getjitstate()
-            v_builder = hop.llops.genmixlevelhelpercall(rtimeshift.before_call,
-                                                        [ts.s_JITState],
-                                                        [v_jitstate],
-                                                     ts.s_ResidualGraphBuilder)
             hop.r_s_popfirstarg()
             args_hs = hop.args_s[:]
             # fixed is always false here
             graph = bk.get_graph_for_call(fnobj.graph, False, args_hs)
             args_r = [self.getrepr(hs) for hs in args_hs]
             args_v = hop.inputargs(*args_r)
-            ARGS = [ts.r_ResidualGraphBuilder.lowleveltype,
-                    ts.r_JITState.lowleveltype]
+            ARGS = [ts.r_JITState.lowleveltype]
             ARGS += [r.lowleveltype for r in args_r]
-            RESULT = ts.r_ResidualGraphBuilder.lowleveltype
+            RESULT = ts.r_RedBox.lowleveltype
             fnptr = lltype.functionptr(lltype.FuncType(ARGS, RESULT),
                                        graph.name,
                                        graph=graph,
                                        _callable = graph.func)
             self.timeshifter.schedule_graph(graph)
-            args_v[:0] = [hop.llops.genconst(fnptr), v_builder, v_jitstate]
-            v_newbuilder = hop.genop('direct_call', args_v, RESULT)
-            return hop.llops.genmixlevelhelpercall(rtimeshift.after_call,
-                                   [ts.s_JITState, ts.s_ResidualGraphBuilder],
-                                   [v_jitstate,    v_newbuilder],
-                                   ts.s_RedBox)
+            args_v[:0] = [hop.llops.genconst(fnptr), v_jitstate]
+            return hop.genop('direct_call', args_v, RESULT)
 
     def translate_op_save_locals(self, hop):
         ts = self.timeshifter

Modified: pypy/dist/pypy/jit/timeshifter/rvalue.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rvalue.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rvalue.py	Sun Sep  3 20:59:48 2006
@@ -38,12 +38,11 @@
     def getgenvar(self, builder):
         return self.genvar
 
-    def enter_block(self, newblock, incoming, memo):
+    def enter_block(self, incoming, memo):
         memo = memo.boxes
         if not self.is_constant() and self not in memo:
-            incoming.append(self.genvar)
+            incoming.append(self)
             memo[self] = None
-            self.genvar = newblock.geninputarg(self.kind)
 
     def forcevar(self, builder, memo):
         if self.is_constant():
@@ -212,11 +211,11 @@
             assert self.genvar
         return self.genvar
 
-    def enter_block(self, newblock, incoming, memo):
+    def enter_block(self, incoming, memo):
         if self.content:
-            self.content.enter_block(newblock, incoming, memo)
+            self.content.enter_block(incoming, memo)
         else:
-            RedBox.enter_block(self, newblock, incoming, memo)
+            RedBox.enter_block(self, incoming, memo)
 
 # ____________________________________________________________
 

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	Sun Sep  3 20:59:48 2006
@@ -5,9 +5,8 @@
 from pypy.jit.hintannotator.model import *
 from pypy.jit.timeshifter.timeshift import HintTimeshift
 from pypy.jit.timeshifter import rtimeshift, rvalue, rtyper as hintrtyper
-from pypy.jit.llabstractinterp.test.test_llabstractinterp import annotation
-from pypy.jit.llabstractinterp.test.test_llabstractinterp import summary
-from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.objspace.flow.model import summary
+from pypy.rpython.lltypesystem import lltype, llmemory, rstr
 from pypy.rpython.objectmodel import hint, keepalive_until_here
 from pypy.rpython.unroll import unrolling_iterable
 from pypy.rpython.annlowlevel import PseudoHighLevelCallable
@@ -26,6 +25,14 @@
 def getargtypes(annotator, values):
     return [annotation(annotator, x) for x in values]
 
+def annotation(a, x):
+    T = lltype.typeOf(x)
+    if T == lltype.Ptr(rstr.STR):
+        t = str
+    else:
+        t = annmodel.lltype_to_annotation(T)
+    return a.typeannotation(t)
+
 def hannotate(func, values, policy=None, inline=None):
     # build the normal ll graphs for ll_function
     t = TranslationContext()
@@ -103,8 +110,8 @@
         #    (True=constant, False=variable) and a value
         #
         graph1 = ha.translator.graphs[0]   # the timeshifted entry point
-        assert len(graph1.getargs()) == 2 + len(values)
-        graph1varargs = graph1.getargs()[2:]
+        assert len(graph1.getargs()) == 1 + len(values)
+        graph1varargs = graph1.getargs()[1:]
         timeshifted_entrypoint_args_s = []
         residual_argtypes = []
         argcolors = []
@@ -131,16 +138,19 @@
             graph1)
         timeshifted_entrypoint = PseudoHighLevelCallable(
             timeshifted_entrypoint_fnptr,
-            [htshift.s_ResidualGraphBuilder, htshift.s_JITState]
+            [htshift.s_JITState]
             + timeshifted_entrypoint_args_s,
-            htshift.s_ResidualGraphBuilder)
+            htshift.s_RedBox)
         FUNC = lltype.FuncType(residual_argtypes, RESTYPE)
         argcolors = unrolling_iterable(argcolors)
         self.argcolors = argcolors
 
         def ml_generate_code(rgenop, *args):
             timeshifted_entrypoint_args = ()
-            builder = rtimeshift.make_builder(rgenop)
+
+            sigtoken = rgenop.sigToken(FUNC)
+            builder, entrypoint, inputargs_gv = rgenop.newgraph(sigtoken)
+            i = 0
             for color in argcolors:
                 if color == "green":
                     llvalue = args[0]
@@ -153,20 +163,24 @@
                     TYPE = lltype.typeOf(llvalue)
                     kind = rgenop.kindToken(TYPE)
                     boxcls = rvalue.ll_redboxcls(TYPE)
-                    gv_arg = rtimeshift.ll_geninputarg(builder, kind)
                     if is_constant:
-                        # ignore the gv_arg above, which is still present
+                        # ignore the inputargs_gv[i], which is still present
                         # to give the residual graph a uniform signature
                         gv_arg = rgenop.genconst(llvalue)
+                    else:
+                        gv_arg = inputargs_gv[i]
                     box = boxcls(kind, gv_arg)
+                    i += 1
                     timeshifted_entrypoint_args += (box,)
-            startblock = rtimeshift.ll_end_setup_builder(builder)
-            endbuilder = timeshifted_entrypoint(builder, None,
+
+            top_jitstate = rtimeshift.JITState(builder)
+            returnbox = timeshifted_entrypoint(top_jitstate,
                                               *timeshifted_entrypoint_args)
-            endbuilder.finish_and_return()
-            sigtoken = rgenop.sigToken(FUNC)
+            gv_ret = returnbox.getgenvar(top_jitstate.curbuilder)
+            top_jitstate.curbuilder.finish_and_return(sigtoken, gv_ret)
+
             gv_generated = rgenop.gencallableconst(sigtoken, "generated",
-                                                   startblock)
+                                                   entrypoint)
             generated = gv_generated.revealconst(lltype.Ptr(FUNC))
             return generated
 

Modified: pypy/dist/pypy/jit/timeshifter/timeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/timeshift.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/timeshift.py	Sun Sep  3 20:59:48 2006
@@ -4,7 +4,7 @@
 from pypy.annotation import model as annmodel
 from pypy.annotation import listdef, dictdef
 from pypy.jit.timeshifter import rvalue, oop
-from pypy.jit.timeshifter.rtimeshift import JITState, ResidualGraphBuilder
+from pypy.jit.timeshifter.rtimeshift import JITState
 from pypy.rpython import rmodel, annlowlevel
 from pypy.rpython.lltypesystem import rtuple, rlist, rdict
 from pypy.jit.timeshifter import rtimeshift
@@ -26,7 +26,8 @@
         self.latestexitindex = -1
         self.annhelper = annlowlevel.MixLevelHelperAnnotator(rtyper)
 
-        self.s_ResidualGraphBuilder, self.r_ResidualGraphBuilder = self.s_r_instanceof(ResidualGraphBuilder)
+        self.s_CodeGenerator, self.r_CodeGenerator = self.s_r_instanceof(
+            cgmodel.CodeGenerator)
         self.s_JITState, self.r_JITState = self.s_r_instanceof(JITState)
         self.s_RedBox, self.r_RedBox = self.s_r_instanceof(rvalue.RedBox)
         self.s_OopSpecDesc, self.r_OopSpecDesc = self.s_r_instanceof(
@@ -38,63 +39,16 @@
         getrepr = self.rtyper.getrepr
 
         bk = rtyper.annotator.bookkeeper
-        box_list_def = listdef.ListDef(None, self.s_RedBox)
-        box_list_def.mutate()
+        box_list_def = listdef.ListDef(None, self.s_RedBox, mutated = True)
         self.s_box_list = annmodel.SomeList(box_list_def)
         self.r_box_list = getrepr(self.s_box_list)
         self.r_box_list.setup()
 
-        box_accum_def = listdef.ListDef(None, self.s_RedBox)
-        box_accum_def.mutate()
-        box_accum_def.resize()
+        box_accum_def = listdef.ListDef(None, self.s_RedBox, resized = True)
         self.s_box_accum = annmodel.SomeList(box_accum_def)
         self.r_box_accum = getrepr(self.s_box_accum)
         self.r_box_accum.setup()
 
-##        def ll_make_builder():
-##            rgenop = RGenOp()
-##            return rtimeshift.make_builder(rgenop)
-
-##        # XXX find a different way to enforce the interface types
-##        self.ll_make_builder_graph = self.annhelper.getgraph(
-##            ll_make_builder,
-##            [], self.s_ResidualGraphBuilder)
-##        self.ll_int_box_graph = self.annhelper.getgraph(
-##            rtimeshift.ll_int_box,
-##            [self.s_ConstOrVar, self.s_ConstOrVar],
-##            self.s_RedBox)
-##        self.ll_addr_box_graph = self.annhelper.getgraph(
-##            rtimeshift.ll_addr_box,
-##            [self.s_ConstOrVar, self.s_ConstOrVar],
-##            self.s_RedBox)
-##        self.ll_double_box_graph = self.annhelper.getgraph(
-##            rtimeshift.ll_int_box,
-##            [self.s_ConstOrVar, self.s_ConstOrVar],
-##            self.s_RedBox)
-##        self.ll_geninputarg_graph = self.annhelper.getgraph(
-##            rtimeshift.ll_geninputarg,
-##            [self.s_ResidualGraphBuilder, self.s_ConstOrVar],
-##            self.s_ConstOrVar)
-##        self.ll_end_setup_builder_graph = self.annhelper.getgraph(
-##            rtimeshift.ll_end_setup_builder,
-##            [self.s_ResidualGraphBuilder],
-##            self.s_Block)
-
-####         self.ll_close_jitstate_graph = self.annhelper.getgraph(
-####             rtimeshift.ll_close_jitstate,
-####             [self.s_JITState],
-####             annmodel.s_None)
-
-##        self.ll_close_builder_graph = self.annhelper.getgraph(
-##            rtimeshift.ll_close_builder,
-##            [self.s_ResidualGraphBuilder],
-##            annmodel.s_None)
-##        self.annhelper.getgraph(
-##            rtimeshift.ll_gencallableconst,
-##            [self.s_ResidualGraphBuilder, annmodel.SomeString(),
-##             self.s_Block, self.s_ConstOrVar],
-##            self.s_ConstOrVar)
-
     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)
@@ -110,7 +64,7 @@
     #
     # then passes the variables to the target of link
     #
-    def getexitindex(self, link, inputargs, args_r, entering_links):
+    def getexitindex(self, link, entering_links):
         self.latestexitindex += 1
         v_jitstate = varoftype(self.r_JITState.lowleveltype, 'jitstate')
         v_boxes = varoftype(self.r_box_accum.lowleveltype, 'boxes')
@@ -120,13 +74,14 @@
         llops = HintLowLevelOpList(self, None)
 
         reenter_vars = [v_jitstate]
+        i = 0
         for var in link.args[1:]:
             if isinstance(var, flowmodel.Constant):
                 reenter_vars.append(var)
                 continue
-            i = inputargs.index(var)
-            r = args_r[i]
+            r = self.hrtyper.bindingrepr(var)
             v_box = self.read_out_box(llops, v_boxes, i)
+            i += 1
             if isinstance(r, RedRepr):
                 reenter_vars.append(v_box)
             else:
@@ -184,6 +139,10 @@
             self.timeshift_block(timeshifted_blocks, entering_links,  block)
         originalblocks = timeshifted_blocks
 
+        inputlinkcounters = {}
+        for block in originalblocks:
+            inputlinkcounters[block] = len(entering_links[block])
+
         returnblock = graph.returnblock
         self.r_returnvalue = self.hrtyper.bindingrepr(returnblock.inputargs[0])
         returnblock.operations = []
@@ -205,7 +164,7 @@
             before_block = self.insert_before_block(block,
                                                     block_entering_links)
             self.insert_bookkeeping_enter(block, before_block,
-                                          len(block_entering_links))
+                                          inputlinkcounters[block])
             self.insert_bookkeeping_leave_block(block, entering_links)
 
         #self.hrtyper.insert_link_conversions(before_returnblock)
@@ -235,16 +194,15 @@
 
     def insert_start_setup(self):
         newstartblock = self.insert_before_block(self.graph.startblock, None, closeblock=True)
-        v_builder = varoftype(self.r_ResidualGraphBuilder.lowleveltype, 'builder')
         v_backstate = varoftype(self.r_JITState.lowleveltype, 'backstate')
         v_jitstate = newstartblock.inputargs[0]
-        newstartblock.inputargs[:1] = [v_builder, v_backstate]
+        newstartblock.inputargs[:1] = [v_backstate]
         llops = HintLowLevelOpList(self, None)
 
         llops.genop('direct_call', [self.c_ll_clearcaches_ptr])
         v_jitstate1 = llops.genmixlevelhelpercall(rtimeshift.enter_graph,
-                               [self.s_ResidualGraphBuilder, self.s_JITState],
-                               [v_builder,                   v_backstate],
+                               [self.s_JITState],
+                               [v_backstate],
                                self.s_JITState)
         llops.append(flowmodel.SpaceOperation('same_as', [v_jitstate1], v_jitstate))
         newstartblock.operations = list(llops)
@@ -260,7 +218,7 @@
                 #elif len(link.args) == 1:
                 #    assert False, "the return block should not be seen"
                     
-    def insert_before_block(self, block, entering_links, closeblock=True):
+    def insert_before_block(self, block, block_entering_links, closeblock=True):
         newinputargs = [copyvar(self.hannotator, var) for var in block.inputargs]
 
         newblock = flowmodel.Block(newinputargs)
@@ -269,7 +227,7 @@
             newblock.isstartblock = True
             self.graph.startblock = newblock
         else:
-            for link in entering_links:
+            for link in block_entering_links:
                 link.settarget(newblock)
 
         if closeblock:
@@ -353,26 +311,9 @@
         v_boxes = rlist.newlist(llops, self.r_box_list, type_erased_v)
         return v_boxes
 
-    # insert before non-join blocks a block with:
-    #
-    #     newjitstate = rtimeshift.enter_block(jitstate, boxes)
-    #     where boxes = [current-redboxes]
-    #
-    # then pass the newjitstate (XXX modified?) and boxes
-    # to the block original; boxes are modified in place
-    #
+
     def bookkeeping_enter_simple(self, args_r, newinputargs, before_block,
                                  llops, v_boxes, is_returnblock=False):
-        v_newjitstate = llops.genmixlevelhelpercall(rtimeshift.enter_block,
-                             [self.s_JITState, self.s_box_list],
-                             [newinputargs[0], v_boxes],
-                             self.s_JITState)
-
-        bridge = before_block.exits[0]
-        # not used any more: v_boxes is not modified by enter_block() nowadays
-        #self.insert_read_out_boxes(bridge, llops, v_newjitstate, v_boxes, args_r, newinputargs)
-        before_block.operations[:] = llops
-
         return None
 
     # insert before join blocks a block with:
@@ -492,126 +433,100 @@
 
         return cache
 
-    # insert after blocks the following logic:
-    # if the original block is the returnblock:
+    # insert at the end  of blocks the following logic:
+    # if the block is the returnblock:
     #
     #     go to dispatch_block(jitstate)
     #
-    # if the original block has just one exit or the exitswitch is green:
+    # if the block has just one exit or the exitswitch is green:
     #
-    #     newjitstate = rtimeshift.leave_block(jitstate)
+    #     <nothing>
     #
-    # if the original block has more than one exit (split case):
+    # if the block has more than one exit (split case):
     #
-    #     res = rtimeshift.leave_block_split(jitstate, exitswitchredbox, exitindex, boxes)
+    #     res = rtimeshift.leave_block_split(jitstate,
+    #                                        exitswitchredbox, exitindex,
+    #                                        true_case_boxes,
+    #                                        false_case_boxes)
     #     where
-    #         boxes =[boxes-for-all-current-red-and-green-values]
+    #         true_case_boxes = [redboxes going into the true case link]
+    #         false_case_boxes = [redbox going into the false case link
+    #             + green values going into it wrapped into redboxes,
+    #               all to be saved for later dispatch]
     #         exitindex = number identifying the false branch of the switch
     #     if res then go to true_exit_block
     #     else go to false_exit_block
     #
     # exitindex is computed by getexitindex, see comment for that method
     #
-    # leave_block_split if the exitswitchredbox is constant just returns its value as res
-    # otherwise returns True and schedule the false case
+    # leave_block_split if the exitswitchredbox is constant just
+    # returns its value as res otherwise returns True
+    # and schedule the false case
     #
     def insert_bookkeeping_leave_block(self, block, entering_links):
-        # XXX wrong with exceptions as much else
-        
-        renamemap = {}
-        rename = lambda v: renamemap.get(v, v)
-        inargs = []
-
-        def introduce(v):
-            if isinstance(v, flowmodel.Variable):
-                if v not in renamemap:
-                    vprime = renamemap[v] = copyvar(self.hannotator, v)
-                    inargs.append(v)
-
-        orig_v_jitstate = block.inputargs[0]
-        introduce(orig_v_jitstate)
-
-        newlinks = []
-
-        v_newjitstate = varoftype(self.r_JITState.lowleveltype, 'jitstate')
-        self.hannotator.bindings[v_newjitstate] = self.s_JITState
-
-        def rename_on_link(v):
-            if v is orig_v_jitstate:
-                return v_newjitstate
-            else:
-                return rename(v)
+        exits = block.exits
+        exitswitch = block.exitswitch
 
-        for link in block.exits:
-            for v in link.args:
-                introduce(v)
-            newlink =  link.copy(rename_on_link)
-            newlink.llexitcase = newlink.exitcase # sanitize the link llexitcase
-            newlinks.append(newlink)
-            target = link.target
-            # update entering_links as necessary
-            if target in entering_links:
-                target_entering_links = entering_links[target]
-                target_entering_links.remove(link)
-                target_entering_links.append(newlink)
-        introduce(block.exitswitch)
-
-        inputargs = [rename(v) for v in inargs]
-        newblock = flowmodel.Block(inputargs)
-        newblock.closeblock(*newlinks)
-            
-        inlink = flowmodel.Link(inargs, newblock)
-        oldexitswitch = block.exitswitch
-        block.exitswitch = None
-        block.recloseblock(inlink)
-
-        llops = HintLowLevelOpList(self, None)
-        if len(newblock.exits) == 0: # this is the original returnblock
-            newblock.recloseblock(flowmodel.Link(newblock.inputargs, self.dispatchblock))
-        elif len(newblock.exits) == 1 or isinstance(self.hrtyper.bindingrepr(oldexitswitch), GreenRepr):
-            newblock.exitswitch = rename(oldexitswitch)
-            v_res = llops.genmixlevelhelpercall(rtimeshift.leave_block,
-                                                [self.s_JITState],
-                                                [rename(orig_v_jitstate)],
-                                                self.s_JITState)     
-
-            llops.append(flowmodel.SpaceOperation('same_as',
-                                   [v_res],
-                                   v_newjitstate))
+        if len(exits) == 0: # this is the original returnblock
+            block.recloseblock(flowmodel.Link(block.inputargs[:1],
+                                              self.dispatchblock))
+        elif (len(exits) == 1 or
+              isinstance(self.hrtyper.bindingrepr(exitswitch), GreenRepr)):
+            pass # nothing to do
         else:
-            v_jitstate = rename(orig_v_jitstate)
-            args_r = []
-            boxes_v = []
-            for var in inputargs[1:]:
-                r = self.hrtyper.bindingrepr(var)
-                args_r.append(r)
-                if isinstance(r, RedRepr):
-                    boxes_v.append(var)
-                elif isinstance(r, GreenRepr):
-                    v_box = self.make_const_box(llops, r, var, v_jitstate)
-                    boxes_v.append(v_box)
-                else:
-                    raise RuntimeError('Unsupported boxtype')
-            
-            v_boxes = self.build_box_list(llops, boxes_v)
-            false_exit = [exit for exit in newblock.exits if exit.exitcase is False][0]
-            exitindex = self.getexitindex(false_exit, inputargs[1:], args_r, entering_links)
+            llops = HintLowLevelOpList(self, None)
+            v_jitstate = self.getjitstate(block)
+            assert len(exits) == 2
+            false_exit, true_exit = exits
+            if true_exit.exitcase is False:
+                true_exit, false_exit = false_exit, true_exit
+            assert true_exit.exitcase is True
+            assert false_exit.exitcase is False
+            # sanitize llexitcase
+            true_exit.llexitcase = True
+            false_exit.llexitcase = False
+            v_boxes_true = self.pack_state_into_boxes(llops,
+                                                      true_exit.args[1:],
+                                                      v_jitstate,
+                                                      pack_greens_too=False)
+            v_boxes_false = self.pack_state_into_boxes(llops,
+                                                       false_exit.args[1:],
+                                                       v_jitstate,
+                                                       pack_greens_too=True)
+            exitindex = self.getexitindex(false_exit, entering_links)
             c_exitindex = rmodel.inputconst(lltype.Signed, exitindex)
             v_res = llops.genmixlevelhelpercall(rtimeshift.leave_block_split,
                                                 [self.s_JITState,
                                                  self.s_RedBox,
                                                  annmodel.SomeInteger(),
+                                                 self.s_box_list,
                                                  self.s_box_list],
                                                 [v_jitstate,
-                                                 rename(oldexitswitch),
+                                                 exitswitch,
                                                  c_exitindex,
-                                                 v_boxes],
+                                                 v_boxes_true,
+                                                 v_boxes_false],
                                                 annmodel.SomeBool())
-            llops.append(flowmodel.SpaceOperation('same_as',
-                                                  [inputargs[0]],
-                                                  v_newjitstate))
-            newblock.exitswitch = v_res
-        newblock.operations[:] = llops
+            block.exitswitch = v_res
+            block.operations.extend(llops)
+
+
+    def pack_state_into_boxes(self, llops, statevars, v_jitstate,
+                              pack_greens_too):
+        boxes_v = []
+        for var in statevars:
+            if isinstance(var, flowmodel.Constant):
+                continue    # it's correspondingly skipped in getexitindex()
+            r = self.hrtyper.bindingrepr(var)
+            if isinstance(r, RedRepr):
+                boxes_v.append(var)
+            elif isinstance(r, GreenRepr):
+                if pack_greens_too:
+                    v_box = self.make_const_box(llops, r, var, v_jitstate)
+                    boxes_v.append(v_box)
+            else:
+                raise RuntimeError('Unsupported boxtype')
+        return self.build_box_list(llops, boxes_v)
 
     # put the following logic in the dispatch block:
     #
@@ -626,13 +541,13 @@
     #
     # the prepare_return_block does:
     #
-    #     builder = prepare_return(jitstate)
+    #     returnbox = prepare_return(jitstate)
     #     where
     #         prepare_return = (lambda jitstate:
     #                           rtimeshift.prepare_return(jitstate, return_cache,
     #                                None))) # XXX return type info
     #         where return_cache is a predefined cache
-    #     return builder 
+    #     return returnbox
     #
     def insert_dispatch_logic(self):
         dispatchblock = self.dispatchblock
@@ -640,8 +555,8 @@
         llops = HintLowLevelOpList(self, None)
 
 
-        v_returnbuilder = varoftype(self.r_ResidualGraphBuilder.lowleveltype, 'builder')
-        returnblock = flowmodel.Block([v_returnbuilder])
+        v_returnbox = varoftype(self.r_RedBox.lowleveltype, 'returnbox')
+        returnblock = flowmodel.Block([v_returnbox])
         returnblock.operations = ()
         self.graph.returnblock = returnblock
         
@@ -685,7 +600,7 @@
         llops = HintLowLevelOpList(self, None)
         v_return_builder = llops.genmixlevelhelpercall(prepare_return,
                           [self.s_JITState], [v_jitstate2],
-                          self.s_ResidualGraphBuilder)
+                          self.s_RedBox)
 
         prepare_return_block.operations = list(llops)
         finishedlink = flowmodel.Link([v_return_builder], returnblock)

Modified: pypy/dist/pypy/jit/timeshifter/vlist.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/vlist.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/vlist.py	Sun Sep  3 20:59:48 2006
@@ -75,19 +75,19 @@
         self.item_boxes = [itembox] * length
         # self.ownbox = ...    set in factory()
 
-    def enter_block(self, newblock, incoming, memo):
+    def enter_block(self, incoming, memo):
         contmemo = memo.containers
         if self not in contmemo:
             contmemo[self] = None
             for box in self.item_boxes:
-                box.enter_block(newblock, incoming, memo)
+                box.enter_block(incoming, memo)
 
     def force_runtime_container(self, builder):
         typedesc = self.typedesc
         boxes = self.item_boxes
         self.item_boxes = None
 
-        args_gv = [None, builder.genconst(len(boxes))]
+        args_gv = [None, builder.rgenop.genconst(len(boxes))]
         gv_list = builder.genop_call(typedesc.tok_ll_newlist,
                                      typedesc.gv_ll_newlist,
                                      args_gv)
@@ -95,7 +95,7 @@
         self.ownbox.content = None
         for i in range(len(boxes)):
             gv_item = boxes[i].getgenvar(builder)
-            args_gv = [gv_list, builder.genconst(i), gv_item]
+            args_gv = [gv_list, builder.rgenop.genconst(i), gv_item]
             builder.genop_call(typedesc.tok_ll_setitem_fast,
                                typedesc.gv_ll_setitem_fast,
                                args_gv)



More information about the Pypy-commit mailing list