[pypy-commit] pypy better-jit-hooks: merge default

fijal noreply at buildbot.pypy.org
Sun Dec 25 17:48:26 CET 2011


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: better-jit-hooks
Changeset: r50855:39462e5a78fc
Date: 2011-12-25 18:47 +0200
http://bitbucket.org/pypy/pypy/changeset/39462e5a78fc/

Log:	merge default

diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py
--- a/lib_pypy/_sqlite3.py
+++ b/lib_pypy/_sqlite3.py
@@ -231,8 +231,10 @@
 sqlite.sqlite3_result_text.argtypes = [c_void_p, c_char_p, c_int, c_void_p]
 sqlite.sqlite3_result_text.restype = None
 
-sqlite.sqlite3_enable_load_extension.argtypes = [c_void_p, c_int]
-sqlite.sqlite3_enable_load_extension.restype = c_int
+HAS_LOAD_EXTENSION = hasattr(sqlite, "sqlite3_enable_load_extension")
+if HAS_LOAD_EXTENSION:
+    sqlite.sqlite3_enable_load_extension.argtypes = [c_void_p, c_int]
+    sqlite.sqlite3_enable_load_extension.restype = c_int
 
 ##########################################
 # END Wrapped SQLite C API and constants
@@ -708,13 +710,14 @@
         from sqlite3.dump import _iterdump
         return _iterdump(self)
 
-    def enable_load_extension(self, enabled):
-        self._check_thread()
-        self._check_closed()
+    if HAS_LOAD_EXTENSION:
+        def enable_load_extension(self, enabled):
+            self._check_thread()
+            self._check_closed()
 
-        rc = sqlite.sqlite3_enable_load_extension(self.db, int(enabled))
-        if rc != SQLITE_OK:
-            raise OperationalError("Error enabling load extension")
+            rc = sqlite.sqlite3_enable_load_extension(self.db, int(enabled))
+            if rc != SQLITE_OK:
+                raise OperationalError("Error enabling load extension")
 
 DML, DQL, DDL = range(3)
 
diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -180,7 +180,12 @@
         if name is None:
             name = pyobj.func_name
         if signature is None:
-            signature = cpython_code_signature(pyobj.func_code)
+            if hasattr(pyobj, '_generator_next_method_of_'):
+                from pypy.interpreter.argument import Signature
+                signature = Signature(['entry'])     # haaaaaack
+                defaults = ()
+            else:
+                signature = cpython_code_signature(pyobj.func_code)
         if defaults is None:
             defaults = pyobj.func_defaults
         self.name = name
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -39,6 +39,7 @@
 from pypy.jit.codewriter.effectinfo import EffectInfo
 from pypy.jit.codewriter import longlong
 from pypy.rlib.rarithmetic import intmask
+from pypy.rlib.objectmodel import compute_unique_id
 
 # darwin requires the stack to be 16 bytes aligned on calls. Same for gcc 4.5.0,
 # better safe than sorry
@@ -147,12 +148,13 @@
     def finish_once(self):
         if self._debug:
             debug_start('jit-backend-counts')
-            for struct in self.loop_run_counters:
-                if struct.bridge:
-                    prefix = 'bridge '
+            for i in range(len(self.loop_run_counters)):
+                struct = self.loop_run_counters[i]
+                if not struct.bridge:
+                    prefix = 'TargetToken(%d)' % struct.number
                 else:
-                    prefix = 'loop '
-                debug_print(prefix + str(struct.number) + ':' + str(struct.i))
+                    prefix = 'bridge ' + str(struct.number)
+                debug_print(prefix + ':' + str(struct.i))
             debug_stop('jit-backend-counts')
 
     def _build_float_constants(self):
@@ -422,8 +424,8 @@
 
         self.setup(looptoken)
         if log:
-            self._register_counter(False, looptoken.number)
-            operations = self._inject_debugging_code(looptoken, operations)
+            operations = self._inject_debugging_code(looptoken, operations,
+                                                     False, looptoken.number)
 
         regalloc = RegAlloc(self, self.cpu.translate_support_code)
         #
@@ -489,8 +491,8 @@
 
         self.setup(original_loop_token)
         if log:
-            self._register_counter(True, descr_number)
-            operations = self._inject_debugging_code(faildescr, operations)
+            operations = self._inject_debugging_code(faildescr, operations,
+                                                     True, descr_number)
 
         arglocs = self.rebuild_faillocs_from_descr(failure_recovery)
         if not we_are_translated():
@@ -597,17 +599,21 @@
         return self.mc.materialize(self.cpu.asmmemmgr, allblocks,
                                    self.cpu.gc_ll_descr.gcrootmap)
 
-    def _register_counter(self, bridge, number):
-        if self._debug:
-            # YYY very minor leak -- we need the counters to stay alive
-            # forever, just because we want to report them at the end
-            # of the process
-            struct = lltype.malloc(DEBUG_COUNTER, flavor='raw',
-                                   track_allocation=False)
-            struct.i = 0
-            struct.bridge = int(bridge)
+    def _register_counter(self, bridge, number, token):
+        # YYY very minor leak -- we need the counters to stay alive
+        # forever, just because we want to report them at the end
+        # of the process
+        struct = lltype.malloc(DEBUG_COUNTER, flavor='raw',
+                               track_allocation=False)
+        struct.i = 0
+        struct.bridge = int(bridge)
+        if bridge:
             struct.number = number
-            self.loop_run_counters.append(struct)
+        else:
+            assert token
+            struct.number = compute_unique_id(token)
+        self.loop_run_counters.append(struct)            
+        return struct
 
     def _find_failure_recovery_bytecode(self, faildescr):
         adr_jump_offset = faildescr._x86_adr_jump_offset
@@ -651,27 +657,37 @@
             targettoken._x86_loop_code += rawstart
         self.target_tokens_currently_compiling = None
 
+    def _append_debugging_code(self, operations, bridge, number, token):
+        counter = self._register_counter(bridge, number, token)
+        c_adr = ConstInt(rffi.cast(lltype.Signed, counter))
+        box = BoxInt()
+        box2 = BoxInt()
+        ops = [ResOperation(rop.GETFIELD_RAW, [c_adr],
+                            box, descr=self.debug_counter_descr),
+               ResOperation(rop.INT_ADD, [box, ConstInt(1)], box2),
+               ResOperation(rop.SETFIELD_RAW, [c_adr, box2],
+                            None, descr=self.debug_counter_descr)]
+        operations.extend(ops)
+        
     @specialize.argtype(1)
-    def _inject_debugging_code(self, looptoken, operations):
+    def _inject_debugging_code(self, looptoken, operations, bridge, number):
         if self._debug:
             # before doing anything, let's increase a counter
             s = 0
             for op in operations:
                 s += op.getopnum()
             looptoken._x86_debug_checksum = s
-            c_adr = ConstInt(rffi.cast(lltype.Signed,
-                                       self.loop_run_counters[-1]))
-            box = BoxInt()
-            box2 = BoxInt()
-            ops = [ResOperation(rop.GETFIELD_RAW, [c_adr],
-                                box, descr=self.debug_counter_descr),
-                   ResOperation(rop.INT_ADD, [box, ConstInt(1)], box2),
-                   ResOperation(rop.SETFIELD_RAW, [c_adr, box2],
-                                None, descr=self.debug_counter_descr)]
-            if operations[0].getopnum() == rop.LABEL:
-                operations = [operations[0]] + ops + operations[1:]
-            else:
-                operations =  ops + operations
+
+            newoperations = []
+            if bridge:
+                self._append_debugging_code(newoperations, bridge, number,
+                                            None)
+            for op in operations:
+                newoperations.append(op)
+                if op.getopnum() == rop.LABEL:
+                    self._append_debugging_code(newoperations, bridge, number,
+                                                op.getdescr())
+            operations = newoperations
         return operations
 
     def _assemble(self, regalloc, operations):
diff --git a/pypy/jit/backend/x86/jump.py b/pypy/jit/backend/x86/jump.py
--- a/pypy/jit/backend/x86/jump.py
+++ b/pypy/jit/backend/x86/jump.py
@@ -17,7 +17,10 @@
         key = src._getregkey()
         if key in srccount:
             if key == dst_locations[i]._getregkey():
-                srccount[key] = -sys.maxint     # ignore a move "x = x"
+                # ignore a move "x = x"
+                # setting any "large enough" negative value is ok, but
+                # be careful of overflows, don't use -sys.maxint
+                srccount[key] = -len(dst_locations) - 1
                 pending_dests -= 1
             else:
                 srccount[key] += 1
diff --git a/pypy/jit/backend/x86/test/test_jump.py b/pypy/jit/backend/x86/test/test_jump.py
--- a/pypy/jit/backend/x86/test/test_jump.py
+++ b/pypy/jit/backend/x86/test/test_jump.py
@@ -20,6 +20,11 @@
     def regalloc_pop(self, loc):
         self.ops.append(('pop', loc))
 
+    def regalloc_immedmem2mem(self, from_loc, to_loc):
+        assert isinstance(from_loc, ConstFloatLoc)
+        assert isinstance(to_loc,   StackLoc)
+        self.ops.append(('immedmem2mem', from_loc, to_loc))
+
     def got(self, expected):
         print '------------------------ comparing ---------------------------'
         for op1, op2 in zip(self.ops, expected):
@@ -244,6 +249,13 @@
         else:
             return pick1()
     #
+    def pick2c():
+        n = random.randrange(-2000, 500)
+        if n >= 0:
+            return ConstFloatLoc(n)    # n is the address, not really used here
+        else:
+            return pick2()
+    #
     def pick_dst(fn, count, seen):
         result = []
         while len(result) < count:
@@ -280,12 +292,12 @@
                 if loc.get_width() > WORD:
                     stack[loc.value+WORD] = 'value-hiword-%d' % i
             else:
-                assert isinstance(loc, ImmedLoc)
+                assert isinstance(loc, (ImmedLoc, ConstFloatLoc))
         return regs1, regs2, stack
     #
     for i in range(500):
         seen = {}
-        src_locations2 = [pick2() for i in range(4)]
+        src_locations2 = [pick2c() for i in range(4)]
         dst_locations2 = pick_dst(pick2, 4, seen)
         src_locations1 = [pick1c() for i in range(5)]
         dst_locations1 = pick_dst(pick1, 5, seen)
@@ -312,9 +324,15 @@
                 return got
             if isinstance(loc, ImmedLoc):
                 return 'const-%d' % loc.value
+            if isinstance(loc, ConstFloatLoc):
+                got = 'constfloat-@%d' % loc.value
+                if loc.get_width() > WORD:
+                    got = (got, 'constfloat-next-@%d' % loc.value)
+                return got
             assert 0, loc
         #
         def write(loc, newvalue):
+            assert (type(newvalue) is tuple) == (loc.get_width() > WORD)
             if isinstance(loc, RegLoc):
                 if loc.is_xmm:
                     regs2[loc.value] = newvalue
@@ -337,10 +355,14 @@
         for op in assembler.ops:
             if op[0] == 'mov':
                 src, dst = op[1:]
-                assert isinstance(src, (RegLoc, StackLoc, ImmedLoc))
-                assert isinstance(dst, (RegLoc, StackLoc))
-                assert not (isinstance(src, StackLoc) and
-                            isinstance(dst, StackLoc))
+                if isinstance(src, ConstFloatLoc):
+                    assert isinstance(dst, RegLoc)
+                    assert dst.is_xmm
+                else:
+                    assert isinstance(src, (RegLoc, StackLoc, ImmedLoc))
+                    assert isinstance(dst, (RegLoc, StackLoc))
+                    assert not (isinstance(src, StackLoc) and
+                                isinstance(dst, StackLoc))
                 write(dst, read(src))
             elif op[0] == 'push':
                 src, = op[1:]
@@ -350,6 +372,11 @@
                 dst, = op[1:]
                 assert isinstance(dst, (RegLoc, StackLoc))
                 write(dst, extrapushes.pop())
+            elif op[0] == 'immedmem2mem':
+                src, dst = op[1:]
+                assert isinstance(src, ConstFloatLoc)
+                assert isinstance(dst, StackLoc)
+                write(dst, read(src, 8))
             else:
                 assert 0, "unknown op: %r" % (op,)
         assert not extrapushes
@@ -358,3 +385,32 @@
             assert read(loc, WORD) == src_values1[i]
         for i, loc in enumerate(dst_locations2):
             assert read(loc, 8) == src_values2[i]
+
+
+def test_overflow_bug():
+    CASE = [
+        (-144, -248),   # \ cycle
+        (-248, -144),   # /
+        (-488, -416),   # \ two usages of -488
+        (-488, -480),   # /
+        (-488, -488),   # - one self-application of -488
+        ]
+    class FakeAssembler:
+        def regalloc_mov(self, src, dst):
+            print "mov", src, dst
+        def regalloc_push(self, x):
+            print "push", x
+        def regalloc_pop(self, x):
+            print "pop", x
+        def regalloc_immedmem2mem(self, x, y):
+            print "?????????????????????????"
+    def main():
+        srclocs = [StackLoc(9999, x, 'i') for x,y in CASE]
+        dstlocs = [StackLoc(9999, y, 'i') for x,y in CASE]
+        remap_frame_layout(FakeAssembler(), srclocs, dstlocs, eax)
+    # it works when run directly
+    main()
+    # but it used to crash when translated,
+    # because of a -sys.maxint-2 overflowing to sys.maxint
+    from pypy.rpython.test.test_llinterp import interpret
+    interpret(main, [])
diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py
--- a/pypy/jit/backend/x86/test/test_runner.py
+++ b/pypy/jit/backend/x86/test/test_runner.py
@@ -519,16 +519,23 @@
         from pypy.tool.logparser import parse_log_file, extract_category
         from pypy.rlib import debug
 
+        targettoken, preambletoken = TargetToken(), TargetToken()
         loop = """
         [i0]
-        label(i0, descr=targettoken)
+        label(i0, descr=preambletoken)
         debug_merge_point('xyz', 0)
         i1 = int_add(i0, 1)
         i2 = int_ge(i1, 10)
         guard_false(i2) []
-        jump(i1, descr=targettoken)
+        label(i1, descr=targettoken)
+        debug_merge_point('xyz', 0)
+        i11 = int_add(i1, 1)
+        i12 = int_ge(i11, 10)
+        guard_false(i12) []
+        jump(i11, descr=targettoken)
         """
-        ops = parse(loop, namespace={'targettoken': TargetToken()})
+        ops = parse(loop, namespace={'targettoken': targettoken,
+                                     'preambletoken': preambletoken})
         debug._log = dlog = debug.DebugLog()
         try:
             self.cpu.assembler.set_debug(True)
@@ -537,11 +544,15 @@
             self.cpu.execute_token(looptoken, 0)
             # check debugging info
             struct = self.cpu.assembler.loop_run_counters[0]
-            assert struct.i == 10
+            assert struct.i == 1
+            struct = self.cpu.assembler.loop_run_counters[1]
+            assert struct.i == 9
             self.cpu.finish_once()
         finally:
             debug._log = None
-        assert ('jit-backend-counts', [('debug_print', 'loop -1:10')]) in dlog
+        l1 = ('debug_print', preambletoken.repr_of_descr() + ':1')
+        l2 = ('debug_print', targettoken.repr_of_descr() + ':9')
+        assert ('jit-backend-counts', [l1, l2]) in dlog
 
     def test_debugger_checksum(self):
         loop = """
diff --git a/pypy/jit/backend/x86/test/test_zrpy_platform.py b/pypy/jit/backend/x86/test/test_zrpy_platform.py
--- a/pypy/jit/backend/x86/test/test_zrpy_platform.py
+++ b/pypy/jit/backend/x86/test/test_zrpy_platform.py
@@ -74,8 +74,8 @@
     myjitdriver = jit.JitDriver(greens = [], reds = ['n'])
 
     def entrypoint(argv):
-        myjitdriver.set_param('threshold', 2)
-        myjitdriver.set_param('trace_eagerness', 0)
+        jit.set_param(myjitdriver, 'threshold', 2)
+        jit.set_param(myjitdriver, 'trace_eagerness', 0)
         n = 16
         while n > 0:
             myjitdriver.can_enter_jit(n=n)
diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py
--- a/pypy/jit/codewriter/call.py
+++ b/pypy/jit/codewriter/call.py
@@ -42,8 +42,7 @@
         except AttributeError:
             pass
 
-        def is_candidate(graph):
-            return policy.look_inside_graph(graph)
+        is_candidate = policy.look_inside_graph
 
         assert len(self.jitdrivers_sd) > 0
         todo = [jd.portal_graph for jd in self.jitdrivers_sd]
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -38,7 +38,8 @@
         else:
             extraprocedures = [procedure]
         metainterp_sd.stats.view(errmsg=errmsg,
-                                 extraprocedures=extraprocedures)
+                                 extraprocedures=extraprocedures,
+                                 metainterp_sd=metainterp_sd)
 
 def create_empty_loop(metainterp, name_prefix=''):
     name = metainterp.staticdata.stats.name_for_new_loop()
@@ -105,7 +106,7 @@
 
 def compile_loop(metainterp, greenkey, start,
                  inputargs, jumpargs,
-                 start_resumedescr, full_preamble_needed=True):
+                 resume_at_jump_descr, full_preamble_needed=True):
     """Try to compile a new procedure by closing the current history back
     to the first operation.
     """
@@ -126,10 +127,11 @@
         part = create_empty_loop(metainterp)
         part.inputargs = inputargs[:]
         h_ops = history.operations
-        part.start_resumedescr = start_resumedescr
+        part.resume_at_jump_descr = resume_at_jump_descr
         part.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(jitcell_token))] + \
                           [h_ops[i].clone() for i in range(start, len(h_ops))] + \
-                          [ResOperation(rop.JUMP, jumpargs, None, descr=jitcell_token)]
+                          [ResOperation(rop.LABEL, jumpargs, None, descr=jitcell_token)]
+
         try:
             optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts)
         except InvalidLoop:
@@ -184,7 +186,7 @@
 
 def compile_retrace(metainterp, greenkey, start,
                     inputargs, jumpargs,
-                    start_resumedescr, partial_trace, resumekey):
+                    resume_at_jump_descr, partial_trace, resumekey):
     """Try to compile a new procedure by closing the current history back
     to the first operation.
     """
@@ -200,7 +202,7 @@
 
     part = create_empty_loop(metainterp)
     part.inputargs = inputargs[:]
-    part.start_resumedescr = start_resumedescr
+    part.resume_at_jump_descr = resume_at_jump_descr
     h_ops = history.operations
 
     part.operations = [partial_trace.operations[-1]] + \
@@ -212,13 +214,12 @@
     try:
         optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts)
     except InvalidLoop:
-        #return None # XXX: Dissable for now
         # Fall back on jumping to preamble
         target_token = label.getdescr()
         assert isinstance(target_token, TargetToken)
         assert target_token.exported_state
         part.operations = [orignial_label] + \
-                          [ResOperation(rop.JUMP, target_token.exported_state.jump_args,
+                          [ResOperation(rop.JUMP, inputargs[:],
                                         None, descr=loop_jitcell_token)]
         try:
             optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts,
@@ -751,7 +752,7 @@
         metainterp_sd.stats.add_jitcell_token(jitcell_token)
 
 
-def compile_trace(metainterp, resumekey, start_resumedescr=None):
+def compile_trace(metainterp, resumekey, resume_at_jump_descr=None):
     """Try to compile a new bridge leading from the beginning of the history
     to some existing place.
     """
@@ -767,7 +768,7 @@
     # clone ops, as optimize_bridge can mutate the ops
 
     new_trace.operations = [op.clone() for op in metainterp.history.operations]
-    new_trace.start_resumedescr = start_resumedescr
+    new_trace.resume_at_jump_descr = resume_at_jump_descr
     metainterp_sd = metainterp.staticdata
     state = metainterp.jitdriver_sd.warmstate
     if isinstance(resumekey, ResumeAtPositionDescr):
diff --git a/pypy/jit/metainterp/graphpage.py b/pypy/jit/metainterp/graphpage.py
--- a/pypy/jit/metainterp/graphpage.py
+++ b/pypy/jit/metainterp/graphpage.py
@@ -12,7 +12,7 @@
     def get_display_text(self):
         return None
 
-def display_procedures(procedures, errmsg=None, highlight_procedures={}):
+def display_procedures(procedures, errmsg=None, highlight_procedures={}, metainterp_sd=None):
     graphs = [(procedure, highlight_procedures.get(procedure, 0))
               for procedure in procedures]
     for graph, highlight in graphs:
@@ -20,7 +20,7 @@
             if is_interesting_guard(op):
                 graphs.append((SubGraph(op.getdescr()._debug_suboperations),
                                highlight))
-    graphpage = ResOpGraphPage(graphs, errmsg)
+    graphpage = ResOpGraphPage(graphs, errmsg, metainterp_sd)
     graphpage.display()
 
 def is_interesting_guard(op):
@@ -36,8 +36,8 @@
 
 class ResOpGraphPage(GraphPage):
 
-    def compute(self, graphs, errmsg=None):
-        resopgen = ResOpGen()
+    def compute(self, graphs, errmsg=None, metainterp_sd=None):
+        resopgen = ResOpGen(metainterp_sd)
         for graph, highlight in graphs:
             resopgen.add_graph(graph, highlight)
         if errmsg:
@@ -50,13 +50,14 @@
     CLUSTERING = True
     BOX_COLOR = (128, 0, 96)
 
-    def __init__(self):
+    def __init__(self, metainterp_sd=None):
         self.graphs = []
         self.highlight_graphs = {}
         self.block_starters = {}    # {graphindex: {set-of-operation-indices}}
         self.all_operations = {}
         self.errmsg = None
         self.target_tokens = {}
+        self.metainterp_sd = metainterp_sd
 
     def op_name(self, graphindex, opindex):
         return 'g%dop%d' % (graphindex, opindex)
@@ -164,7 +165,14 @@
         opindex = opstartindex
         while True:
             op = operations[opindex]
-            lines.append(op.repr(graytext=True))
+            op_repr = op.repr(graytext=True)
+            if op.getopnum() == rop.DEBUG_MERGE_POINT:
+                jd_sd = self.metainterp_sd.jitdrivers_sd[op.getarg(0).getint()]
+                if jd_sd._get_printable_location_ptr:
+                    s = jd_sd.warmstate.get_location_str(op.getarglist()[2:])
+                    s = s.replace(',', '.') # we use comma for argument splitting
+                    op_repr = "debug_merge_point(%d, '%s')" % (op.getarg(1).getint(), s)
+            lines.append(op_repr)
             if is_interesting_guard(op):
                 tgt = op.getdescr()._debug_suboperations[0]
                 tgt_g, tgt_i = self.all_operations[tgt]
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -705,6 +705,9 @@
 
         self.virtual_state = None
         self.exported_state = None
+
+    def repr_of_descr(self):
+        return 'TargetToken(%d)' % compute_unique_id(self)
         
 class TreeLoop(object):
     inputargs = None
@@ -712,7 +715,7 @@
     call_pure_results = None
     logops = None
     quasi_immutable_deps = None
-    start_resumedescr = None
+    resume_at_jump_descr = None
 
     def _token(*args):
         raise Exception("TreeLoop.token is killed")
@@ -1004,25 +1007,6 @@
         # a jump back to itself and possibly a few bridges ending with finnish.
         # Only the operations within the loop formed by that single jump will
         # be counted.
-
-        # XXX hacked version, ignore and remove me when jit-targets is merged.
-        loops = self.get_all_loops()
-        loops = [loop for loop in loops if 'Preamble' not in repr(loop)] #XXX
-        assert len(loops) == 1
-        loop, = loops
-        jumpop = loop.operations[-1]
-        assert jumpop.getopnum() == rop.JUMP
-        insns = {}
-        for op in loop.operations:
-            opname = op.getopname()
-            insns[opname] = insns.get(opname, 0) + 1
-        return self._check_insns(insns, expected, check)
-
-    def check_simple_loop(self, expected=None, **check):
-        # Usefull in the simplest case when we have only one trace ending with
-        # a jump back to itself and possibly a few bridges ending with finnish.
-        # Only the operations within the loop formed by that single jump will
-        # be counted.
         loops = self.get_all_loops()
         assert len(loops) == 1
         loop = loops[0]
@@ -1081,7 +1065,7 @@
         if option.view:
             self.view()
 
-    def view(self, errmsg=None, extraprocedures=[]):
+    def view(self, errmsg=None, extraprocedures=[], metainterp_sd=None):
         from pypy.jit.metainterp.graphpage import display_procedures
         procedures = self.get_all_loops()[:]
         for procedure in extraprocedures:
@@ -1093,7 +1077,7 @@
             if hasattr(procedure, '_looptoken_number') and (
                procedure._looptoken_number in self.invalidated_token_numbers):
                 highlight_procedures.setdefault(procedure, 2)
-        display_procedures(procedures, errmsg, highlight_procedures)
+        display_procedures(procedures, errmsg, highlight_procedures, metainterp_sd)
 
 # ----------------------------------------------------------------
 
diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py
--- a/pypy/jit/metainterp/logger.py
+++ b/pypy/jit/metainterp/logger.py
@@ -5,7 +5,7 @@
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp.history import Const, ConstInt, Box, \
-     BoxInt, ConstFloat, BoxFloat, AbstractFailDescr
+     BoxInt, ConstFloat, BoxFloat, AbstractFailDescr, TargetToken
 
 class Logger(object):
 
@@ -135,6 +135,13 @@
             fail_args = ''
         return s_offset + res + op.getopname() + '(' + args + ')' + fail_args
 
+    def _log_inputarg_setup_ops(self, op):
+        target_token = op.getdescr()
+        if isinstance(target_token, TargetToken):
+            if target_token.exported_state:
+                for op in target_token.exported_state.inputarg_setup_ops:
+                    debug_print('    ' + self.repr_of_resop(op))
+        
     def _log_operations(self, inputargs, operations, ops_offset):
         if not have_debug_prints():
             return
@@ -146,6 +153,8 @@
         for i in range(len(operations)):
             op = operations[i]
             debug_print(self.repr_of_resop(operations[i], ops_offset))
+            if op.getopnum() == rop.LABEL:
+                self._log_inputarg_setup_ops(op)
         if ops_offset and None in ops_offset:
             offset = ops_offset[None]
             debug_print("+%d: --end of the loop--" % offset)
diff --git a/pypy/jit/metainterp/optimize.py b/pypy/jit/metainterp/optimize.py
--- a/pypy/jit/metainterp/optimize.py
+++ b/pypy/jit/metainterp/optimize.py
@@ -5,58 +5,3 @@
     """Raised when the optimize*.py detect that the loop that
     we are trying to build cannot possibly make sense as a
     long-running loop (e.g. it cannot run 2 complete iterations)."""
-
-class RetraceLoop(JitException):
-    """ Raised when inlining a short preamble resulted in an
-        InvalidLoop. This means the optimized loop is too specialized
-        to be useful here, so we trace it again and produced a second
-        copy specialized in some different way.
-    """
-
-# ____________________________________________________________
-
-def optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts):
-    debug_start("jit-optimize")
-    try:
-        return _optimize_loop(metainterp_sd, old_loop_tokens, loop,
-                              enable_opts)
-    finally:
-        debug_stop("jit-optimize")
-
-def _optimize_loop(metainterp_sd, old_loop_tokens, loop, enable_opts):
-    from pypy.jit.metainterp.optimizeopt import optimize_loop_1
-    loop.logops = metainterp_sd.logger_noopt.log_loop(loop.inputargs,
-                                                      loop.operations)
-    # XXX do we really still need a list?
-    if old_loop_tokens:
-        return old_loop_tokens[0]
-    optimize_loop_1(metainterp_sd, loop, enable_opts)
-    return None
-
-# ____________________________________________________________
-
-def optimize_bridge(metainterp_sd, old_loop_tokens, bridge, enable_opts,
-                    inline_short_preamble=True, retraced=False):
-    debug_start("jit-optimize")
-    try:
-        return _optimize_bridge(metainterp_sd, old_loop_tokens, bridge,
-                                enable_opts,
-                                inline_short_preamble, retraced)
-    finally:
-        debug_stop("jit-optimize")
-
-def _optimize_bridge(metainterp_sd, old_loop_tokens, bridge, enable_opts,
-                     inline_short_preamble, retraced=False):
-    from pypy.jit.metainterp.optimizeopt import optimize_bridge_1
-    bridge.logops = metainterp_sd.logger_noopt.log_loop(bridge.inputargs,
-                                                        bridge.operations)
-    if old_loop_tokens:
-        old_loop_token = old_loop_tokens[0]
-        bridge.operations[-1].setdescr(old_loop_token)   # patch jump target
-        optimize_bridge_1(metainterp_sd, bridge, enable_opts,
-                          inline_short_preamble, retraced)
-        return old_loop_tokens[0]
-        #return bridge.operations[-1].getdescr()
-    return None
-
-# ____________________________________________________________
diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py
--- a/pypy/jit/metainterp/optimizeopt/__init__.py
+++ b/pypy/jit/metainterp/optimizeopt/__init__.py
@@ -51,34 +51,6 @@
 
     return optimizations, unroll
 
-
-def optimize_loop_1(metainterp_sd, loop, enable_opts,
-                    inline_short_preamble=True, retraced=False):
-    """Optimize loop.operations to remove internal overheadish operations.
-    """
-
-    optimizations, unroll = build_opt_chain(metainterp_sd, enable_opts,
-                                            inline_short_preamble, retraced)
-    if unroll:
-        optimize_unroll(metainterp_sd, loop, optimizations)
-    else:
-        optimizer = Optimizer(metainterp_sd, loop, optimizations)
-        optimizer.propagate_all_forward()
-
-def optimize_bridge_1(metainterp_sd, bridge, enable_opts,
-                      inline_short_preamble=True, retraced=False):
-    """The same, but for a bridge. """
-    enable_opts = enable_opts.copy()
-    try:
-        del enable_opts['unroll']
-    except KeyError:
-        pass
-    optimize_loop_1(metainterp_sd, bridge, enable_opts,
-                    inline_short_preamble, retraced)
-
-if __name__ == '__main__':
-    print ALL_OPTS_NAMES
-
 def optimize_trace(metainterp_sd, loop, enable_opts, inline_short_preamble=True):
     """Optimize loop.operations to remove internal overheadish operations.
     """
@@ -96,3 +68,6 @@
     finally:
         debug_stop("jit-optimize")
         
+if __name__ == '__main__':
+    print ALL_OPTS_NAMES
+
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -453,6 +453,7 @@
 
     def clear_newoperations(self):
         self._newoperations = []
+        self.seen_results = {}
 
     def make_equal_to(self, box, value, replace=False):
         assert isinstance(value, OptValue)
diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py
--- a/pypy/jit/metainterp/optimizeopt/simplify.py
+++ b/pypy/jit/metainterp/optimizeopt/simplify.py
@@ -35,6 +35,9 @@
         pass
 
     def optimize_LABEL(self, op):
+        descr = op.getdescr()
+        if isinstance(descr, JitCellToken):
+            return self.optimize_JUMP(op.copy_and_change(rop.JUMP))
         self.last_label_descr = op.getdescr()
         self.emit_operation(op)
         
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
@@ -9,14 +9,14 @@
 class BaseTestMultiLabel(BaseTest):
     enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll"
 
-    def optimize_loop(self, ops, expected):
+    def optimize_loop(self, ops, expected, expected_shorts=None):
         loop = self.parse(ops)
         if expected != "crash!":
             expected = self.parse(expected)
 
         part = TreeLoop('part')
         part.inputargs = loop.inputargs
-        part.start_resumedescr = FakeDescrWithSnapshot()
+        part.resume_at_jump_descr = FakeDescrWithSnapshot()
         token = loop.original_jitcell_token
 
         optimized = TreeLoop('optimized')
@@ -33,15 +33,17 @@
             if nxt < len(loop.operations):
                 label = loop.operations[nxt]
                 assert label.getopnum() == rop.LABEL
-                jumpop = ResOperation(rop.JUMP, label.getarglist(),
-                                      None, descr=token)
-                operations.append(jumpop)
+                if label.getdescr() is None:
+                    label.setdescr(token)
+                operations.append(label)
             part.operations = operations
+
             self._do_optimize_loop(part, None)
             if part.operations[-1].getopnum() == rop.LABEL:
                 last_label = [part.operations.pop()]
             else:
                 last_label = []
+            
             optimized.operations.extend(part.operations)
             prv = nxt + 1
         
@@ -54,9 +56,32 @@
             print 'Failed!'
         print
 
+        shorts = [op.getdescr().short_preamble
+                  for op in optimized.operations
+                  if op.getopnum() == rop.LABEL]
+
+        if expected_shorts:
+            for short in shorts:
+                print
+                print "Short preamble:"
+                print '\n'.join([str(o) for o in short])
+
+
         assert expected != "crash!", "should have raised an exception"
         self.assert_equal(optimized, expected)
 
+        if expected_shorts:
+            assert len(shorts) == len(expected_shorts)
+            for short, expected_short in zip(shorts, expected_shorts):
+                expected_short = self.parse(expected_short)
+                short_preamble = TreeLoop('short preamble')
+                assert short[0].getopnum() == rop.LABEL
+                short_preamble.inputargs = short[0].getarglist()
+                short_preamble.operations = short
+                self.assert_equal(short_preamble, expected_short,
+                                  text_right='expected short preamble')
+
+        
         return optimized
 
     def test_simple(self):
@@ -194,8 +219,168 @@
         """
         with raises(InvalidLoop):
             self.optimize_loop(ops, ops)
-        
+
+    def test_two_intermediate_labels_basic_1(self):
+        ops = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        label(p1, i1)
+        i3 = getfield_gc(p1, descr=valuedescr)
+        i4 = int_add(i1, i3)
+        label(p1, i4)
+        i5 = int_add(i4, 1)
+        jump(p1, i5)
+        """
+        expected = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        label(p1, i1, i2)
+        i4 = int_add(i1, i2)
+        label(p1, i4)
+        i5 = int_add(i4, 1)
+        jump(p1, i5)
+        """
+        short1 = """
+        [p1, i1]
+        label(p1, i1)
+        i2 = getfield_gc(p1, descr=valuedescr)
+        jump(p1, i1, i2)
+        """
+        short2 = """
+        [p1, i1]
+        label(p1, i1)
+        jump(p1, i1)
+        """
+        self.optimize_loop(ops, expected, expected_shorts=[short1, short2])
+
+    def test_two_intermediate_labels_basic_2(self):
+        ops = """
+        [p1, i1]
+        i2 = int_add(i1, 1)
+        label(p1, i1)
+        i3 = getfield_gc(p1, descr=valuedescr)
+        i4 = int_add(i1, i3)
+        label(p1, i4)
+        i5 = getfield_gc(p1, descr=valuedescr)
+        i6 = int_add(i4, i5)
+        jump(p1, i6)
+        """
+        expected = """
+        [p1, i1]
+        i2 = int_add(i1, 1)
+        label(p1, i1)
+        i3 = getfield_gc(p1, descr=valuedescr)
+        i4 = int_add(i1, i3)
+        label(p1, i4, i3)
+        i6 = int_add(i4, i3)
+        jump(p1, i6, i3)
+        """
+        short1 = """
+        [p1, i1]
+        label(p1, i1)
+        jump(p1, i1)
+        """
+        short2 = """
+        [p1, i1]
+        label(p1, i1)
+        i2 = getfield_gc(p1, descr=valuedescr)
+        jump(p1, i1, i2)
+        """
+        self.optimize_loop(ops, expected, expected_shorts=[short1, short2])
+
+    def test_two_intermediate_labels_both(self):
+        ops = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        label(p1, i1)
+        i3 = getfield_gc(p1, descr=valuedescr)
+        i4 = int_add(i1, i3)
+        label(p1, i4)
+        i5 = getfield_gc(p1, descr=valuedescr)
+        i6 = int_mul(i4, i5)
+        jump(p1, i6)
+        """
+        expected = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        label(p1, i1, i2)
+        i4 = int_add(i1, i2)
+        label(p1, i4, i2)
+        i6 = int_mul(i4, i2)
+        jump(p1, i6, i2)
+        """
+        short = """
+        [p1, i1]
+        label(p1, i1)
+        i2 = getfield_gc(p1, descr=valuedescr)        
+        jump(p1, i1, i2)
+        """
+        self.optimize_loop(ops, expected, expected_shorts=[short, short])
+
+    def test_import_across_multiple_labels_basic(self):
+        # Not supported, juts make sure we get a functional trace
+        ops = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        label(p1, i1)
+        i3 = int_add(i1, 1)
+        label(p1, i1)
+        i4 = getfield_gc(p1, descr=valuedescr)
+        i5 = int_add(i4, 1)
+        jump(p1, i5)
+        """
+        self.optimize_loop(ops, ops)
+
+    def test_import_across_multiple_labels_with_duplication(self):
+        # Not supported, juts make sure we get a functional trace
+        ops = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        label(p1, i2)
+        i3 = int_add(i2, 1)
+        label(p1, i2)
+        i4 = getfield_gc(p1, descr=valuedescr)
+        i5 = int_add(i4, 1)
+        jump(p1, i5)
+        """
+        exported = """
+        [p1, i1]
+        i2 = getfield_gc(p1, descr=valuedescr)
+        i6 = same_as(i2)
+        label(p1, i2)
+        i3 = int_add(i2, 1)
+        label(p1, i2)
+        i4 = getfield_gc(p1, descr=valuedescr)
+        i5 = int_add(i4, 1)
+        jump(p1, i5)
+        """
+        self.optimize_loop(ops, exported)
     
+    def test_import_virtual_across_multiple_labels(self):
+        ops = """
+        [p0, i1]
+        i1a = int_add(i1, 1)
+        pv = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(pv, i1a, descr=valuedescr)
+        label(pv, i1)
+        i2 = int_mul(i1, 3)
+        label(pv, i2)
+        i3 = getfield_gc(pv, descr=valuedescr)
+        i4 = int_add(i3, i2)
+        jump(pv, i4)
+        """
+        expected = """
+        [p0, i1]
+        i1a = int_add(i1, 1)
+        i5 = same_as(i1a)
+        label(i1a, i1)
+        i2 = int_mul(i1, 3)
+        label(i1a, i2)
+        i4 = int_add(i1a, i2)
+        jump(i1a, i4)
+        """
+        self.optimize_loop(ops, expected)
+
 class TestLLtype(BaseTestMultiLabel, LLtypeMixin):
     pass
 
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -4,7 +4,7 @@
     LLtypeMixin, BaseTest, Storage, _sortboxes, convert_old_style_to_targets)
 import pypy.jit.metainterp.optimizeopt.optimizer as optimizeopt
 import pypy.jit.metainterp.optimizeopt.virtualize as virtualize
-from pypy.jit.metainterp.optimizeopt import optimize_loop_1, ALL_OPTS_DICT, build_opt_chain
+from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT, build_opt_chain
 from pypy.jit.metainterp.optimize import InvalidLoop
 from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt
 from pypy.jit.metainterp.history import TreeLoop, JitCellToken, TargetToken
@@ -4211,7 +4211,6 @@
         preamble = """
         [p0]
         i0 = strlen(p0)
-        i3 = same_as(i0) # Should be killed by backend        
         jump(p0)
         """
         expected = """
@@ -5668,8 +5667,7 @@
         p3 = newstr(i3)
         copystrcontent(p1, p3, 0, 0, i1)
         copystrcontent(p2, p3, 0, i1, i2)
-        i7 = same_as(i2)        
-        jump(p2, p3, i7)
+        jump(p2, p3, i2)
         """
         expected = """
         [p1, p2, i1]
@@ -5744,9 +5742,7 @@
         copystrcontent(p1, p5, 0, 0, i1)
         copystrcontent(p2, p5, 0, i1, i2)
         copystrcontent(p3, p5, 0, i12, i3)
-        i129 = same_as(i2)
-        i130 = same_as(i3)
-        jump(p2, p3, p5, i129, i130)
+        jump(p2, p3, p5, i2, i3)
         """
         expected = """
         [p1, p2, p3, i1, i2]
@@ -5959,8 +5955,7 @@
         p4 = newstr(i5)
         copystrcontent(p1, p4, i1, 0, i3)
         copystrcontent(p2, p4, 0, i3, i4)
-        i9 = same_as(i4)
-        jump(p4, i1, i2, p2, i5, i3, i9)
+        jump(p4, i1, i2, p2, i5, i3, i4)
         """
         expected = """
         [p1, i1, i2, p2, i5, i3, i4]
@@ -6082,9 +6077,7 @@
         copystrcontent(p2, p4, 0, i1, i2)
         i0 = call(0, p3, p4, descr=strequaldescr)
         escape(i0)
-        i11 = same_as(i1)
-        i12 = same_as(i2)
-        jump(p1, p2, p3, i3, i11, i12)
+        jump(p1, p2, p3, i3, i1, i2)
         """
         expected = """
         [p1, p2, p3, i3, i1, i2]
@@ -6304,7 +6297,6 @@
         i1 = strlen(p1)
         i0 = int_eq(i1, 0)
         escape(i0)
-        i3 = same_as(i1)        
         jump(p1, i0)
         """
         self.optimize_strunicode_loop_extradescrs(ops, expected, preamble)
@@ -6350,9 +6342,7 @@
         copystrcontent(p2, p4, 0, i1, i2)
         i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr)
         escape(i0)
-        i11 = same_as(i1)
-        i12 = same_as(i2)
-        jump(p1, p2, i3, i11, i12)
+        jump(p1, p2, i3, i1, i2)
         """
         expected = """
         [p1, p2, i3, i1, i2]
@@ -6925,8 +6915,7 @@
         [p9]
         i843 = strlen(p9)
         call(i843, descr=nonwritedescr)
-        i0 = same_as(i843)
-        jump(p9, i0)
+        jump(p9, i843)
         """
         short = """
         [p9]
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_util.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py
@@ -430,18 +430,18 @@
 
         preamble = TreeLoop('preamble')
         preamble.inputargs = inputargs
-        preamble.start_resumedescr = FakeDescrWithSnapshot()
+        preamble.resume_at_jump_descr = FakeDescrWithSnapshot()
 
         token = JitCellToken() 
         preamble.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(token))] + \
                               operations +  \
-                              [ResOperation(rop.JUMP, jump_args, None, descr=token)]
+                              [ResOperation(rop.LABEL, jump_args, None, descr=token)]
         self._do_optimize_loop(preamble, call_pure_results)
 
         assert preamble.operations[-1].getopnum() == rop.LABEL
 
         inliner = Inliner(inputargs, jump_args)
-        loop.start_resumedescr = preamble.start_resumedescr
+        loop.resume_at_jump_descr = preamble.resume_at_jump_descr
         loop.operations = [preamble.operations[-1]] + \
                           [inliner.inline_op(op, clone=False) for op in cloned_operations] + \
                           [ResOperation(rop.JUMP, [inliner.inline_arg(a) for a in jump_args],
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -3,7 +3,7 @@
 from pypy.jit.metainterp.compile import ResumeGuardDescr
 from pypy.jit.metainterp.history import TreeLoop, TargetToken, JitCellToken
 from pypy.jit.metainterp.jitexc import JitException
-from pypy.jit.metainterp.optimize import InvalidLoop, RetraceLoop
+from pypy.jit.metainterp.optimize import InvalidLoop
 from pypy.jit.metainterp.optimizeopt.optimizer import *
 from pypy.jit.metainterp.optimizeopt.generalize import KillHugeIntBounds
 from pypy.jit.metainterp.inliner import Inliner
@@ -51,10 +51,10 @@
     distinction anymore)"""
 
     inline_short_preamble = True
-    did_import = False
     
     def __init__(self, metainterp_sd, loop, optimizations):
         self.optimizer = UnrollableOptimizer(metainterp_sd, loop, optimizations)
+        self.boxes_created_this_iteration = None
 
     def fix_snapshot(self, jump_args, snapshot):
         if snapshot is None:
@@ -71,7 +71,6 @@
         loop = self.optimizer.loop
         self.optimizer.clear_newoperations()
 
-
         start_label = loop.operations[0]
         if start_label.getopnum() == rop.LABEL:
             loop.operations = loop.operations[1:]
@@ -82,7 +81,7 @@
             start_label = None            
 
         jumpop = loop.operations[-1]
-        if jumpop.getopnum() == rop.JUMP:
+        if jumpop.getopnum() == rop.JUMP or jumpop.getopnum() == rop.LABEL:
             loop.operations = loop.operations[:-1]
         else:
             jumpop = None
@@ -91,48 +90,87 @@
         self.optimizer.propagate_all_forward(clear=False)
 
         if not jumpop:
-            return 
-        if self.jump_to_already_compiled_trace(jumpop):
-            # Found a compiled trace to jump to
-            if self.did_import:
-
-                self.close_bridge(start_label)
-                self.finilize_short_preamble(start_label)
             return
 
         cell_token = jumpop.getdescr()
         assert isinstance(cell_token, JitCellToken)
         stop_label = ResOperation(rop.LABEL, jumpop.getarglist(), None, TargetToken(cell_token))
 
-        if not self.did_import: # Enforce the previous behaviour of always peeling  exactly one iteration (for now)
-            self.optimizer.flush()
-            KillHugeIntBounds(self.optimizer).apply()
+        
+        if jumpop.getopnum() == rop.JUMP:
+            if self.jump_to_already_compiled_trace(jumpop):
+                # Found a compiled trace to jump to
+                if self.short:
+                    # Construct our short preamble
+                    assert start_label
+                    self.close_bridge(start_label)
+                return
 
-            loop.operations = self.optimizer.get_newoperations()
-            self.export_state(stop_label)
-            loop.operations.append(stop_label)            
-        else:
-            assert stop_label
+            if start_label and self.jump_to_start_label(start_label, stop_label):
+                # Initial label matches, jump to it
+                jumpop = ResOperation(rop.JUMP, stop_label.getarglist(), None,
+                                      descr=start_label.getdescr())
+                if self.short:
+                    # Construct our short preamble
+                    self.close_loop(start_label, jumpop)
+                else:
+                    self.optimizer.send_extra_operation(jumpop)
+                return
+
+            if cell_token.target_tokens:
+                limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit
+                if cell_token.retraced_count < limit:
+                    cell_token.retraced_count += 1
+                    debug_print('Retracing (%d/%d)' % (cell_token.retraced_count, limit))
+                else:
+                    debug_print("Retrace count reached, jumping to preamble")
+                    assert cell_token.target_tokens[0].virtual_state is None
+                    jumpop.setdescr(cell_token.target_tokens[0])
+                    self.optimizer.send_extra_operation(jumpop)
+                    return
+
+        # Found nothing to jump to, emit a label instead
+        
+        if self.short:
+            # Construct our short preamble
             assert start_label
-            stop_target = stop_label.getdescr()
-            start_target = start_label.getdescr()
-            assert isinstance(stop_target, TargetToken)
-            assert isinstance(start_target, TargetToken)
-            assert stop_target.targeting_jitcell_token is start_target.targeting_jitcell_token
-            jumpop = ResOperation(rop.JUMP, stop_label.getarglist(), None, descr=start_label.getdescr())
+            self.close_bridge(start_label)
 
-            self.close_loop(jumpop)
-            self.finilize_short_preamble(start_label)
+        self.optimizer.flush()
+        KillHugeIntBounds(self.optimizer).apply()
+
+        loop.operations = self.optimizer.get_newoperations()
+        self.export_state(stop_label)
+        loop.operations.append(stop_label)
+
+    def jump_to_start_label(self, start_label, stop_label):
+        if not start_label or not stop_label:
+            return False
+        
+        stop_target = stop_label.getdescr()
+        start_target = start_label.getdescr()
+        assert isinstance(stop_target, TargetToken)
+        assert isinstance(start_target, TargetToken)
+        if stop_target.targeting_jitcell_token is not start_target.targeting_jitcell_token:
+            return False
+
+        return True
+
+        #args = stop_label.getarglist()
+        #modifier = VirtualStateAdder(self.optimizer)
+        #virtual_state = modifier.get_virtual_state(args)
+        #if self.initial_virtual_state.generalization_of(virtual_state):
+        #    return True
+        
 
     def export_state(self, targetop):
         original_jump_args = targetop.getarglist()
         jump_args = [self.getvalue(a).get_key_box() for a in original_jump_args]
 
-        assert self.optimizer.loop.start_resumedescr
-        start_resumedescr = self.optimizer.loop.start_resumedescr.clone_if_mutable()
-        assert isinstance(start_resumedescr, ResumeGuardDescr)
-        start_resumedescr.rd_snapshot = self.fix_snapshot(jump_args, start_resumedescr.rd_snapshot)
-        # FIXME: I dont thnik we need fix_snapshot anymore
+        assert self.optimizer.loop.resume_at_jump_descr
+        resume_at_jump_descr = self.optimizer.loop.resume_at_jump_descr.clone_if_mutable()
+        assert isinstance(resume_at_jump_descr, ResumeGuardDescr)
+        resume_at_jump_descr.rd_snapshot = self.fix_snapshot(jump_args, resume_at_jump_descr.rd_snapshot)
 
         modifier = VirtualStateAdder(self.optimizer)
         virtual_state = modifier.get_virtual_state(jump_args)
@@ -141,26 +179,21 @@
         inputargs = virtual_state.make_inputargs(values, self.optimizer)
         short_inputargs = virtual_state.make_inputargs(values, self.optimizer, keyboxes=True)
 
-        constant_inputargs = {}
-        for box in jump_args: 
-            const = self.get_constant_box(box)
-            if const:
-                constant_inputargs[box] = const
 
-        short_boxes = ShortBoxes(self.optimizer, inputargs + constant_inputargs.keys())
-        aliased_vrituals = {}
-        for i in range(len(original_jump_args)):
-            if original_jump_args[i] is not jump_args[i]:
-                if values[i].is_virtual():
-                    aliased_vrituals[original_jump_args[i]] = jump_args[i] 
-                else:
-                    short_boxes.alias(original_jump_args[i], jump_args[i])
+        if self.boxes_created_this_iteration is not None:
+            for box in self.inputargs:
+                self.boxes_created_this_iteration[box] = True
+
+        short_boxes = ShortBoxes(self.optimizer, inputargs,
+                                 self.boxes_created_this_iteration)
 
         self.optimizer.clear_newoperations()
-        for box in short_inputargs:
-            value = self.getvalue(box)
-            if value.is_virtual():
-                value.force_box(self.optimizer)
+        for i in range(len(original_jump_args)):
+            if values[i].is_virtual():
+                values[i].force_box(self.optimizer)
+            if original_jump_args[i] is not jump_args[i]:
+                op = ResOperation(rop.SAME_AS, [jump_args[i]], original_jump_args[i])
+                self.optimizer.emit_operation(op)
         inputarg_setup_ops = self.optimizer.get_newoperations()
 
         target_token = targetop.getdescr()
@@ -168,78 +201,82 @@
         targetop.initarglist(inputargs)
         target_token.virtual_state = virtual_state
         target_token.short_preamble = [ResOperation(rop.LABEL, short_inputargs, None)]
-        target_token.start_resumedescr = start_resumedescr
-        target_token.exported_state = ExportedState(constant_inputargs, short_boxes,
-                                                    inputarg_setup_ops, self.optimizer,
-                                                    aliased_vrituals, jump_args)
+        target_token.resume_at_jump_descr = resume_at_jump_descr
+
+        exported_values = {}
+        for box in inputargs:
+            exported_values[box] = self.optimizer.getvalue(box)
+        for op in short_boxes.operations():
+            if op and op.result:
+                box = op.result
+                exported_values[box] = self.optimizer.getvalue(box)
+            
+        target_token.exported_state = ExportedState(short_boxes, inputarg_setup_ops,
+                                                    exported_values)
 
     def import_state(self, targetop):
-        self.did_import = False
-        if not targetop:
-            # FIXME: Set up some sort of empty state with no virtuals?
+        if not targetop: # Trace did not start with a label
+            self.inputargs = self.optimizer.loop.inputargs
+            self.short = None
+            self.initial_virtual_state = None
             return
+
+        self.inputargs = targetop.getarglist()
         target_token = targetop.getdescr()
-        if not target_token:
-            return
         assert isinstance(target_token, TargetToken)
         exported_state = target_token.exported_state
         if not exported_state:
-            # FIXME: Set up some sort of empty state with no virtuals
+            # No state exported, construct one without virtuals
+            self.short = None
+            modifier = VirtualStateAdder(self.optimizer)
+            virtual_state = modifier.get_virtual_state(self.inputargs)
+            self.initial_virtual_state = virtual_state
             return
-        self.did_import = True
         
         self.short = target_token.short_preamble[:]
         self.short_seen = {}
-        self.short_boxes = exported_state.short_boxes.clone()
-        for box, const in exported_state.constant_inputargs.items():
-            self.short_seen[box] = True
-        self.imported_state = exported_state
-        self.inputargs = targetop.getarglist()
+        self.short_boxes = exported_state.short_boxes
+        self.short_resume_at_jump_descr = target_token.resume_at_jump_descr
         self.initial_virtual_state = target_token.virtual_state
-        self.start_resumedescr = target_token.start_resumedescr
 
         seen = {}
         for box in self.inputargs:
             if box in seen:
                 continue
             seen[box] = True
-            preamble_value = exported_state.optimizer.getvalue(box)
+            preamble_value = exported_state.exported_values[box]
             value = self.optimizer.getvalue(box)
             value.import_from(preamble_value, self.optimizer)
 
-        for newbox, oldbox in self.short_boxes.aliases.items():
-            self.optimizer.make_equal_to(newbox, self.optimizer.getvalue(oldbox))
-        
         # Setup the state of the new optimizer by emiting the
         # short operations and discarding the result
         self.optimizer.emitting_dissabled = True
         for op in exported_state.inputarg_setup_ops:
             self.optimizer.send_extra_operation(op)
+
         seen = {}
-        
         for op in self.short_boxes.operations():
             self.ensure_short_op_emitted(op, self.optimizer, seen)
             if op and op.result:
-                preamble_value = exported_state.optimizer.getvalue(op.result)
+                preamble_value = exported_state.exported_values[op.result]
                 value = self.optimizer.getvalue(op.result)
                 if not value.is_virtual():
                     imp = ValueImporter(self, preamble_value, op)
                     self.optimizer.importable_values[value] = imp
                 newvalue = self.optimizer.getvalue(op.result)
                 newresult = newvalue.get_key_box()
+                # note that emitting here SAME_AS should not happen, but
+                # in case it does, we would prefer to be suboptimal in asm
+                # to a fatal RPython exception.
                 if newresult is not op.result and not newvalue.is_constant():
                     self.short_boxes.alias(newresult, op.result)
                     op = ResOperation(rop.SAME_AS, [op.result], newresult)
-                    self.optimizer._newoperations = [op] + self.optimizer._newoperations # XXX
-                    #self.optimizer.getvalue(op.result).box = op.result # FIXME: HACK!!!
+                    self.optimizer._newoperations = [op] + self.optimizer._newoperations
         self.optimizer.flush()
         self.optimizer.emitting_dissabled = False
 
-        for box, key_box in exported_state.aliased_vrituals.items():
-            self.optimizer.make_equal_to(box, self.getvalue(key_box))
-
     def close_bridge(self, start_label):
-        inputargs = self.inputargs        
+        inputargs = self.inputargs
         short_jumpargs = inputargs[:]
 
         # We dont need to inline the short preamble we are creating as we are conneting
@@ -249,8 +286,6 @@
         newoperations = self.optimizer.get_newoperations()
         self.boxes_created_this_iteration = {}
         i = 0
-        while newoperations[i].getopnum() != rop.LABEL:
-            i += 1
         while i < len(newoperations):
             op = newoperations[i]
             self.boxes_created_this_iteration[op.result] = True
@@ -262,11 +297,11 @@
             i += 1
             newoperations = self.optimizer.get_newoperations()
         self.short.append(ResOperation(rop.JUMP, short_jumpargs, None, descr=start_label.getdescr()))
-        
-    def close_loop(self, jumpop):
+        self.finilize_short_preamble(start_label)
+
+    def close_loop(self, start_label, jumpop):
         virtual_state = self.initial_virtual_state
         short_inputargs = self.short[0].getarglist()
-        constant_inputargs = self.imported_state.constant_inputargs
         inputargs = self.inputargs
         short_jumpargs = inputargs[:]
 
@@ -289,8 +324,6 @@
                     raise InvalidLoop
             args[short_inputargs[i]] = jmp_to_short_args[i]
         self.short_inliner = Inliner(short_inputargs, jmp_to_short_args)
-        for box, const in constant_inputargs.items():
-            self.short_inliner.argmap[box] = const
         for op in self.short[1:]:
             newop = self.short_inliner.inline_op(op)
             self.optimizer.send_extra_operation(newop)
@@ -299,8 +332,6 @@
         newoperations = self.optimizer.get_newoperations()
         self.boxes_created_this_iteration = {}
         i = j = 0
-        while newoperations[i].getopnum() != rop.LABEL:
-            i += 1
         while i < len(newoperations) or j < len(jumpargs):
             if i == len(newoperations):
                 while j < len(jumpargs):
@@ -353,6 +384,8 @@
             assert isinstance(target_token, TargetToken)
             target_token.targeting_jitcell_token.retraced_count = sys.maxint
             
+        self.finilize_short_preamble(start_label)
+            
     def finilize_short_preamble(self, start_label):
         short = self.short
         assert short[-1].getopnum() == rop.JUMP
@@ -365,7 +398,7 @@
             if op.is_guard():
                 op = op.clone()
                 op.setfailargs(None)
-                descr = target_token.start_resumedescr.clone_if_mutable()
+                descr = target_token.resume_at_jump_descr.clone_if_mutable()
                 op.setdescr(descr)
                 short[i] = op
 
@@ -381,13 +414,11 @@
                 newargs[i] = a.clonebox()
                 boxmap[a] = newargs[i]
         inliner = Inliner(short_inputargs, newargs)
-        for box, const in self.imported_state.constant_inputargs.items():
-            inliner.argmap[box] = const
         for i in range(len(short)):
             short[i] = inliner.inline_op(short[i])
 
-        target_token.start_resumedescr = self.start_resumedescr.clone_if_mutable()            
-        inliner.inline_descr_inplace(target_token.start_resumedescr)
+        target_token.resume_at_jump_descr = target_token.resume_at_jump_descr.clone_if_mutable()
+        inliner.inline_descr_inplace(target_token.resume_at_jump_descr)
 
         # Forget the values to allow them to be freed
         for box in short[0].getarglist():
@@ -398,31 +429,6 @@
         target_token.short_preamble = self.short
         target_token.exported_state = None
 
-        
-    def FIXME_old_stuff():
-            preamble_optimizer = self.optimizer
-            loop.preamble.quasi_immutable_deps = (
-                self.optimizer.quasi_immutable_deps)
-            self.optimizer = self.optimizer.new()
-            loop.quasi_immutable_deps = self.optimizer.quasi_immutable_deps
-
-            
-            loop.inputargs = inputargs
-            args = [preamble_optimizer.getvalue(self.short_boxes.original(a)).force_box(preamble_optimizer)\
-                    for a in inputargs]
-            jmp = ResOperation(rop.JUMP, args, None)
-            jmp.setdescr(loop.token)
-            loop.preamble.operations.append(jmp)
-
-            loop.operations = self.optimizer.get_newoperations()
-            maxguards = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.max_retrace_guards
-            
-            if self.optimizer.emitted_guards > maxguards:
-                loop.preamble.token.retraced_count = sys.maxint
-
-            if short:
-                pass
-
     def ensure_short_op_emitted(self, op, optimizer, seen):
         if op is None:
             return
@@ -450,7 +456,7 @@
             if not isinstance(a, Const) and a not in self.short_seen:
                 self.add_op_to_short(self.short_boxes.producer(a), emit, guards_needed)
         if op.is_guard():
-            descr = self.start_resumedescr.clone_if_mutable()
+            descr = self.short_resume_at_jump_descr.clone_if_mutable()
             op.setdescr(descr)
 
         if guards_needed and self.short_boxes.has_producer(op.result):
@@ -549,7 +555,7 @@
 
                 for guard in extra_guards:
                     if guard.is_guard():
-                        descr = target.start_resumedescr.clone_if_mutable()
+                        descr = target.resume_at_jump_descr.clone_if_mutable()
                         inliner.inline_descr_inplace(descr)
                         guard.setdescr(descr)
                     self.optimizer.send_extra_operation(guard)
@@ -566,20 +572,7 @@
                     self.optimizer.send_extra_operation(jumpop)
                 return True
         debug_stop('jit-log-virtualstate')
-
-        if self.did_import:
-            return False
-        limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit
-        if cell_token.retraced_count<limit:
-            cell_token.retraced_count += 1
-            debug_print('Retracing (%d/%d)' % (cell_token.retraced_count, limit))
-            return False
-        else:
-            debug_print("Retrace count reached, jumping to preamble")
-            assert cell_token.target_tokens[0].virtual_state is None
-            jumpop.setdescr(cell_token.target_tokens[0])
-            self.optimizer.send_extra_operation(jumpop)
-            return True
+        return False
 
 class ValueImporter(object):
     def __init__(self, unroll, value, op):
@@ -592,12 +585,7 @@
         self.unroll.add_op_to_short(self.op, False, True)        
 
 class ExportedState(object):
-    def __init__(self, constant_inputargs,
-                 short_boxes, inputarg_setup_ops, optimizer, aliased_vrituals,
-                 jump_args):
-        self.constant_inputargs = constant_inputargs
+    def __init__(self, short_boxes, inputarg_setup_ops, exported_values):
         self.short_boxes = short_boxes
         self.inputarg_setup_ops = inputarg_setup_ops
-        self.optimizer = optimizer
-        self.aliased_vrituals = aliased_vrituals
-        self.jump_args = jump_args
+        self.exported_values = exported_values
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -559,13 +559,13 @@
     pass
 
 class ShortBoxes(object):
-    def __init__(self, optimizer, surviving_boxes):
+    def __init__(self, optimizer, surviving_boxes, availible_boxes=None):
         self.potential_ops = {}
         self.alternatives = {}
         self.synthetic = {}
-        self.aliases = {}
         self.rename = {}
         self.optimizer = optimizer
+        self.availible_boxes = availible_boxes
 
         if surviving_boxes is not None:
             for box in surviving_boxes:
@@ -581,12 +581,9 @@
                 except BoxNotProducable:
                     pass
 
-    def clone(self):
-        sb = ShortBoxes(self.optimizer, None)
-        sb.aliases.update(self.aliases)
-        sb.short_boxes = {}
-        sb.short_boxes.update(self.short_boxes)
-        return sb
+            self.short_boxes_in_production = None # Not needed anymore
+        else:
+            self.short_boxes = {}
 
     def prioritized_alternatives(self, box):
         if box not in self.alternatives:
@@ -639,6 +636,8 @@
             return
         if box in self.short_boxes_in_production:
             raise BoxNotProducable
+        if self.availible_boxes is not None and box not in self.availible_boxes:
+            raise BoxNotProducable
         self.short_boxes_in_production[box] = True
         
         if box in self.potential_ops:
@@ -690,13 +689,3 @@
 
     def has_producer(self, box):
         return box in self.short_boxes
-
-    def alias(self, newbox, oldbox):
-        if not isinstance(oldbox, Const) and newbox not in self.short_boxes:
-            self.short_boxes[newbox] = self.short_boxes[oldbox]
-        self.aliases[newbox] = oldbox
-
-    def original(self, box):
-        while box in self.aliases:
-            box = self.aliases[box]
-        return box
diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py
--- a/pypy/jit/metainterp/optimizeopt/vstring.py
+++ b/pypy/jit/metainterp/optimizeopt/vstring.py
@@ -44,7 +44,7 @@
 class __extend__(optimizer.OptValue):
     """New methods added to the base class OptValue for this file."""
 
-    def getstrlen(self, string_optimizer, mode):
+    def getstrlen(self, string_optimizer, mode, lengthbox):
         if mode is mode_string:
             s = self.get_constant_string_spec(mode_string)
             if s is not None:
@@ -57,7 +57,8 @@
             return None
         self.ensure_nonnull()
         box = self.force_box(string_optimizer)
-        lengthbox = BoxInt()
+        if lengthbox is None:
+            lengthbox = BoxInt()
         string_optimizer.emit_operation(ResOperation(mode.STRLEN, [box], lengthbox))
         return lengthbox
 
@@ -73,7 +74,7 @@
         # Copies the pointer-to-string 'self' into the target string
         # given by 'targetbox', at the specified offset.  Returns the offset
         # at the end of the copy.
-        lengthbox = self.getstrlen(string_optimizer, mode)
+        lengthbox = self.getstrlen(string_optimizer, mode, None)
         srcbox = self.force_box(string_optimizer)
         return copy_str_content(string_optimizer, srcbox, targetbox,
                                 CONST_0, offsetbox, lengthbox, mode)
@@ -102,7 +103,7 @@
                 return
         assert self.source_op is not None
         self.box = box = self.source_op.result
-        lengthbox = self.getstrlen(optforce, self.mode)
+        lengthbox = self.getstrlen(optforce, self.mode, None)
         op = ResOperation(self.mode.NEWSTR, [lengthbox], box)
         if not we_are_translated():
             op.name = 'FORCE'
@@ -135,7 +136,7 @@
         self._chars = longerlist[start:stop]
         # slice the 'longerlist', which may also contain Nones
 
-    def getstrlen(self, _, mode):
+    def getstrlen(self, _, mode, lengthbox):
         if self._lengthbox is None:
             self._lengthbox = ConstInt(len(self._chars))
         return self._lengthbox
@@ -216,12 +217,12 @@
         self.left = left
         self.right = right
 
-    def getstrlen(self, string_optimizer, mode):
+    def getstrlen(self, string_optimizer, mode, lengthbox):
         if self.lengthbox is None:
-            len1box = self.left.getstrlen(string_optimizer, mode)
+            len1box = self.left.getstrlen(string_optimizer, mode, None)
             if len1box is None:
                 return None
-            len2box = self.right.getstrlen(string_optimizer, mode)
+            len2box = self.right.getstrlen(string_optimizer, mode, None)
             if len2box is None:
                 return None
             self.lengthbox = _int_add(string_optimizer, len1box, len2box)
@@ -268,7 +269,7 @@
         self.vstart = vstart
         self.vlength = vlength
 
-    def getstrlen(self, optforce, mode):
+    def getstrlen(self, optforce, mode, lengthbox):
         return self.vlength.force_box(optforce)
 
     @specialize.arg(1)
@@ -285,7 +286,7 @@
         return None
 
     def string_copy_parts(self, string_optimizer, targetbox, offsetbox, mode):
-        lengthbox = self.getstrlen(string_optimizer, mode)
+        lengthbox = self.getstrlen(string_optimizer, mode, None)
         return copy_str_content(string_optimizer,
                                 self.vstr.force_box(string_optimizer), targetbox,
                                 self.vstart.force_box(string_optimizer), offsetbox,
@@ -360,7 +361,7 @@
     string_optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox))
     return resbox
 
-def _strgetitem(string_optimizer, strbox, indexbox, mode):
+def _strgetitem(string_optimizer, strbox, indexbox, mode, resbox=None):
     if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt):
         if mode is mode_string:
             s = strbox.getref(lltype.Ptr(rstr.STR))
@@ -368,7 +369,8 @@
         else:
             s = strbox.getref(lltype.Ptr(rstr.UNICODE))
             return ConstInt(ord(s.chars[indexbox.getint()]))
-    resbox = BoxInt()
+    if resbox is None:
+        resbox = BoxInt()
     string_optimizer.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox],
                                                  resbox))
     return resbox
@@ -434,10 +436,13 @@
     def _optimize_STRGETITEM(self, op, mode):
         value = self.getvalue(op.getarg(0))
         vindex = self.getvalue(op.getarg(1))
-        vresult = self.strgetitem(value, vindex, mode)
-        self.make_equal_to(op.result, vresult)
+        vresult = self.strgetitem(value, vindex, mode, op.result)
+        if op.result in self.optimizer.values:
+            assert self.getvalue(op.result) is vresult
+        else:
+            self.make_equal_to(op.result, vresult)
 
-    def strgetitem(self, value, vindex, mode):
+    def strgetitem(self, value, vindex, mode, resbox=None):
         value.ensure_nonnull()
         #
         if value.is_virtual() and isinstance(value, VStringSliceValue):
@@ -454,7 +459,7 @@
                     return result
         #
         if isinstance(value, VStringConcatValue) and vindex.is_constant():
-            len1box = value.left.getstrlen(self, mode)
+            len1box = value.left.getstrlen(self, mode, None)
             if isinstance(len1box, ConstInt):
                 index = vindex.box.getint()
                 len1 = len1box.getint()
@@ -464,7 +469,7 @@
                     vindex = optimizer.ConstantValue(ConstInt(index - len1))
                     return self.strgetitem(value.right, vindex, mode)
         #
-        resbox = _strgetitem(self, value.force_box(self), vindex.force_box(self), mode)
+        resbox = _strgetitem(self, value.force_box(self), vindex.force_box(self), mode, resbox)
         return self.getvalue(resbox)
 
     def optimize_STRLEN(self, op):
@@ -474,8 +479,11 @@
 
     def _optimize_STRLEN(self, op, mode):
         value = self.getvalue(op.getarg(0))
-        lengthbox = value.getstrlen(self, mode)
-        self.make_equal_to(op.result, self.getvalue(lengthbox))
+        lengthbox = value.getstrlen(self, mode, op.result)
+        if op.result in self.optimizer.values:
+            assert self.getvalue(op.result) is self.getvalue(lengthbox)
+        elif op.result is not lengthbox:
+            self.make_equal_to(op.result, self.getvalue(lengthbox))
 
     def optimize_COPYSTRCONTENT(self, op):
         self._optimize_COPYSTRCONTENT(op, mode_string)
@@ -594,8 +602,8 @@
         v1 = self.getvalue(op.getarg(1))
         v2 = self.getvalue(op.getarg(2))
         #
-        l1box = v1.getstrlen(None, mode)
-        l2box = v2.getstrlen(None, mode)
+        l1box = v1.getstrlen(None, mode, None)
+        l2box = v2.getstrlen(None, mode, None)
         if (l1box is not None and l2box is not None and
             isinstance(l1box, ConstInt) and
             isinstance(l2box, ConstInt) and
@@ -624,15 +632,15 @@
         return False
 
     def handle_str_equal_level1(self, v1, v2, resultbox, mode):
-        l2box = v2.getstrlen(None, mode)
+        l2box = v2.getstrlen(None, mode, None)
         if isinstance(l2box, ConstInt):
             if l2box.value == 0:
-                lengthbox = v1.getstrlen(self, mode)
+                lengthbox = v1.getstrlen(self, mode, None)
                 seo = self.optimizer.send_extra_operation
                 seo(ResOperation(rop.INT_EQ, [lengthbox, CONST_0], resultbox))
                 return True
             if l2box.value == 1:
-                l1box = v1.getstrlen(None, mode)
+                l1box = v1.getstrlen(None, mode, None)
                 if isinstance(l1box, ConstInt) and l1box.value == 1:
                     # comparing two single chars
                     vchar1 = self.strgetitem(v1, optimizer.CVAL_ZERO, mode)
@@ -668,7 +676,7 @@
         return False
 
     def handle_str_equal_level2(self, v1, v2, resultbox, mode):
-        l2box = v2.getstrlen(None, mode)
+        l2box = v2.getstrlen(None, mode, None)
         if isinstance(l2box, ConstInt):
             if l2box.value == 1:
                 vchar = self.strgetitem(v2, optimizer.CVAL_ZERO, mode)
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -1548,11 +1548,6 @@
 
 # ____________________________________________________________
 
-class RetraceState(object):
-    def __init__(self, metainterp, live_arg_boxes):
-        self.merge_point = len(metainterp.current_merge_points) - 1
-        self.live_arg_boxes = live_arg_boxes
-
 class MetaInterp(object):
     in_recursion = 0
 
@@ -2061,7 +2056,7 @@
         cell = self.jitdriver_sd.warmstate.jit_cell_at_key(greenkey)
         return cell.get_procedure_token()
         
-    def compile_loop(self, original_boxes, live_arg_boxes, start, start_resumedescr):
+    def compile_loop(self, original_boxes, live_arg_boxes, start, resume_at_jump_descr):
         num_green_args = self.jitdriver_sd.num_green_args
         greenkey = original_boxes[:num_green_args]
         if not self.partial_trace:
@@ -2071,13 +2066,13 @@
             target_token = compile.compile_retrace(self, greenkey, start,
                                                    original_boxes[num_green_args:],
                                                    live_arg_boxes[num_green_args:],
-                                                   start_resumedescr, self.partial_trace,
+                                                   resume_at_jump_descr, self.partial_trace,
                                                    self.resumekey)
         else:
             target_token = compile.compile_loop(self, greenkey, start,
                                                 original_boxes[num_green_args:],
                                                 live_arg_boxes[num_green_args:],
-                                                start_resumedescr)
+                                                resume_at_jump_descr)
             if target_token is not None:
                 assert isinstance(target_token, TargetToken)
                 self.jitdriver_sd.warmstate.attach_procedure_to_interp(greenkey, target_token.targeting_jitcell_token)
@@ -2089,7 +2084,7 @@
             jitcell_token = target_token.targeting_jitcell_token
             self.raise_continue_running_normally(live_arg_boxes, jitcell_token)
 
-    def compile_trace(self, live_arg_boxes, start_resumedescr):
+    def compile_trace(self, live_arg_boxes, resume_at_jump_descr):
         num_green_args = self.jitdriver_sd.num_green_args
         greenkey = live_arg_boxes[:num_green_args]
         target_jitcell_token = self.get_procedure_token(greenkey)
@@ -2101,7 +2096,7 @@
         self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None,
                             descr=target_jitcell_token)
         try:
-            target_token = compile.compile_trace(self, self.resumekey, start_resumedescr)
+            target_token = compile.compile_trace(self, self.resumekey, resume_at_jump_descr)
         finally:
             self.history.operations.pop()     # remove the JUMP
         if target_token is not None: # raise if it *worked* correctly
@@ -2109,43 +2104,6 @@
             jitcell_token = target_token.targeting_jitcell_token
             self.raise_continue_running_normally(live_arg_boxes, jitcell_token)
 
-    def compile_bridge_and_loop(self, original_boxes, live_arg_boxes, start,
-                                bridge_arg_boxes, start_resumedescr):
-        num_green_args = self.jitdriver_sd.num_green_args
-        original_inputargs = self.history.inputargs
-        greenkey = original_boxes[:num_green_args]
-        old_loop_tokens = self.get_compiled_merge_points(greenkey)
-        original_operations = self.history.operations
-        self.history.inputargs = original_boxes[num_green_args:]
-        greenkey = original_boxes[:num_green_args]
-        self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None)
-        loop_token = compile.compile_new_loop(self, [], greenkey, start,
-                                              start_resumedescr, False)
-        self.history.operations.pop()     # remove the JUMP
-        if loop_token is None:
-            self.history.inputargs = original_inputargs
-            self.history.operations = original_operations
-            return
-
-        if loop_token.short_preamble:
-            old_loop_tokens[0].short_preamble.extend(loop_token.short_preamble)
-
-        self.history.inputargs = original_inputargs
-        self.history.operations = self.history.operations[:start]
-
-        self.history.record(rop.JUMP, bridge_arg_boxes[num_green_args:], None)
-        try:
-            target_loop_token = compile.compile_new_bridge(self,
-                                                           #[loop_token],
-                                                           old_loop_tokens,
-                                                           self.resumekey,
-                                                           True)
-        except RetraceLoop:
-            assert False
-        assert target_loop_token is not None
-        self.raise_continue_running_normally(live_arg_boxes,
-                                             old_loop_tokens[0])
-
     def compile_done_with_this_frame(self, exitbox):
         self.gen_store_back_in_virtualizable()
         # temporarily put a JUMP to a pseudo-loop
diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py
--- a/pypy/jit/metainterp/test/test_virtual.py
+++ b/pypy/jit/metainterp/test/test_virtual.py
@@ -860,12 +860,15 @@
         assert res == f(10)
         self.check_resops(jump=2)
 
-    def test_nested_loops(self):
+    def test_nested_loops_1(self):
         class Int(object):
             def __init__(self, val):
                 self.val = val
-        myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'sa', 'i', 'j'])
         bytecode = "iajb+JI"
+        def get_printable_location(i):
+            return "%d: %s" % (i, bytecode[i])
+        myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'sa', 'i', 'j'],
+                                get_printable_location=get_printable_location)
         def f(n):
             pc = sa = 0
             i = j = Int(0)
diff --git a/pypy/jit/metainterp/test/test_virtualstate.py b/pypy/jit/metainterp/test/test_virtualstate.py
--- a/pypy/jit/metainterp/test/test_virtualstate.py
+++ b/pypy/jit/metainterp/test/test_virtualstate.py
@@ -11,7 +11,6 @@
 from pypy.jit.metainterp.optimizeopt.intutils import IntBound
 from pypy.jit.metainterp.history import TreeLoop, JitCellToken
 from pypy.jit.metainterp.optimizeopt.test.test_optimizeopt import FakeMetaInterpStaticData
-from pypy.jit.metainterp.optimize import RetraceLoop
 from pypy.jit.metainterp.resoperation import ResOperation, rop
 
 class TestBasic:
@@ -449,7 +448,7 @@
         if hasattr(self, 'callinfocollection'):
             metainterp_sd.callinfocollection = self.callinfocollection
         #
-        bridge.start_resumedescr = FakeDescrWithSnapshot()
+        bridge.resume_at_jump_descr = FakeDescrWithSnapshot()
         optimize_trace(metainterp_sd, bridge, self.enable_opts)
 
         
diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py
--- a/pypy/module/_multiprocessing/interp_connection.py
+++ b/pypy/module/_multiprocessing/interp_connection.py
@@ -6,7 +6,7 @@
     OperationError, wrap_oserror, operationerrfmt)
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rlib.rarithmetic import intmask
-from pypy.rlib import rpoll
+from pypy.rlib import rpoll, rsocket
 import sys
 
 READABLE = 1
@@ -252,7 +252,9 @@
         # "header" and the "body" of the message and send them at once.
         message = lltype.malloc(rffi.CCHARP.TO, size + 4, flavor='raw')
         try:
-            rffi.cast(rffi.UINTP, message)[0] = rffi.r_uint(size) # XXX htonl!
+            length = rffi.r_uint(rsocket.htonl(
+                    rffi.cast(lltype.Unsigned, size)))
+            rffi.cast(rffi.UINTP, message)[0] = length
             i = size - 1
             while i >= 0:
                 message[4 + i] = buffer[offset + i]
@@ -264,7 +266,8 @@
     def do_recv_string(self, space, buflength, maxlength):
         with lltype.scoped_alloc(rffi.CArrayPtr(rffi.UINT).TO, 1) as length_ptr:
             self._recvall(space, rffi.cast(rffi.CCHARP, length_ptr), 4)
-            length = intmask(length_ptr[0])
+            length = intmask(rsocket.ntohl(
+                    rffi.cast(lltype.Unsigned, length_ptr[0])))
         if length > maxlength: # bad message, close connection
             self.flags &= ~READABLE
             if self.flags == 0:
diff --git a/pypy/module/_multiprocessing/test/test_connection.py b/pypy/module/_multiprocessing/test/test_connection.py
--- a/pypy/module/_multiprocessing/test/test_connection.py
+++ b/pypy/module/_multiprocessing/test/test_connection.py
@@ -37,6 +37,9 @@
     def test_connection(self):
         rhandle, whandle = self.make_pair()
 
+        whandle.send_bytes("abc")
+        assert rhandle.recv_bytes(100) == "abc"
+
         obj = [1, 2.0, "hello"]
         whandle.send(obj)
         obj2 = rhandle.recv()
@@ -150,4 +153,20 @@
         import _multiprocessing
 
         raises(IOError, _multiprocessing.Connection, -1)
-        raises(IOError, _multiprocessing.Connection, -15)
\ No newline at end of file
+        raises(IOError, _multiprocessing.Connection, -15)
+
+    def test_byte_order(self):
+        # The exact format of net strings (length in network byte
+        # order) is important for interoperation with others
+        # implementations.
+        rhandle, whandle = self.make_pair()
+        whandle.send_bytes("abc")
+        whandle.send_bytes("defg")
+        import socket
+        sock = socket.fromfd(rhandle.fileno(),
+                             socket.AF_INET, socket.SOCK_STREAM)
+        data1 = sock.recv(7)
+        assert data1 == '\x00\x00\x00\x03abc'
+        data2 = sock.recv(8)
+        assert data2 == '\x00\x00\x00\x04defg'
+
diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -45,6 +45,8 @@
 import pypy.module.cpyext.longobject
 import pypy.module.cpyext.listobject
 import pypy.module.cpyext.sequence
+import pypy.module.cpyext.buffer
+import pypy.module.cpyext.bufferobject
 import pypy.module.cpyext.eval
 import pypy.module.cpyext.import_
 import pypy.module.cpyext.mapping
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -317,6 +317,10 @@
 
 INTERPLEVEL_API = {}
 FUNCTIONS = {}
+
+# These are C symbols which cpyext will export, but which are defined in .c
+# files somewhere in the implementation of cpyext (rather than being defined in
+# RPython).
 SYMBOLS_C = [
     'Py_FatalError', 'PyOS_snprintf', 'PyOS_vsnprintf', 'PyArg_Parse',
     'PyArg_ParseTuple', 'PyArg_UnpackTuple', 'PyArg_ParseTupleAndKeywords',
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/buffer.py
@@ -0,0 +1,11 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import (
+    cpython_api, CANNOT_FAIL, Py_buffer)
+
+ at cpython_api([lltype.Ptr(Py_buffer), lltype.Char], rffi.INT_real, error=CANNOT_FAIL)
+def PyBuffer_IsContiguous(space, view, fortran):
+    """Return 1 if the memory defined by the view is C-style (fortran is
+    'C') or Fortran-style (fortran is 'F') contiguous or either one
+    (fortran is 'A').  Return 0 otherwise."""
+    # PyPy only supports contiguous Py_buffers for now.
+    return space.wrap(1)
diff --git a/pypy/module/cpyext/bufferobject.py b/pypy/module/cpyext/bufferobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/bufferobject.py
@@ -0,0 +1,66 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import (
+    cpython_api, Py_ssize_t, cpython_struct, bootstrap_function,
+    PyObjectFields, PyObject)
+from pypy.module.cpyext.pyobject import make_typedescr, Py_DecRef
+from pypy.interpreter.buffer import Buffer, StringBuffer, SubBuffer
+
+
+PyBufferObjectStruct = lltype.ForwardReference()
+PyBufferObject = lltype.Ptr(PyBufferObjectStruct)
+PyBufferObjectFields = PyObjectFields + (
+    ("b_base", PyObject),
+    ("b_ptr", rffi.VOIDP),
+    ("b_size", Py_ssize_t),
+    ("b_offset", Py_ssize_t),
+    ("b_readonly", rffi.INT),
+    ("b_hash", rffi.LONG),
+    )
+
+cpython_struct("PyBufferObject", PyBufferObjectFields, PyBufferObjectStruct)
+
+ at bootstrap_function
+def init_bufferobject(space):
+    "Type description of PyBufferObject"
+    make_typedescr(space.gettypefor(Buffer).instancetypedef,
+                   basestruct=PyBufferObject.TO,
+                   attach=buffer_attach,
+                   dealloc=buffer_dealloc,
+                   realize=buffer_realize)
+
+def buffer_attach(space, py_obj, w_obj):
+    """
+    Fills a newly allocated PyBufferObject with the given (str) buffer object.
+    """
+    py_buf = rffi.cast(PyBufferObject, py_obj)
+    py_buf.c_b_offset = 0
+    rffi.setintfield(py_buf, 'c_b_readonly', 1)
+    rffi.setintfield(py_buf, 'c_b_hash', -1)
+
+    if isinstance(w_obj, SubBuffer):
+        py_buf.c_b_offset = w_obj.offset
+        w_obj = w_obj.buffer
+
+    if isinstance(w_obj, StringBuffer):
+        py_buf.c_b_base = rffi.cast(PyObject, 0) # space.wrap(w_obj.value)
+        py_buf.c_b_ptr = rffi.cast(rffi.VOIDP, rffi.str2charp(w_obj.as_str()))
+        py_buf.c_b_size = w_obj.getlength()
+    else:
+        raise Exception("Fail fail fail fail fail")
+
+
+def buffer_realize(space, py_obj):
+    """
+    Creates the buffer in the PyPy interpreter from a cpyext representation.
+    """
+    raise Exception("realize fail fail fail")
+
+
+
+ at cpython_api([PyObject], lltype.Void, external=False)
+def buffer_dealloc(space, py_obj):
+    py_buf = rffi.cast(PyBufferObject, py_obj)
+    Py_DecRef(space, py_buf.c_b_base)
+    rffi.free_charp(rffi.cast(rffi.CCHARP, py_buf.c_b_ptr))
+    from pypy.module.cpyext.object import PyObject_dealloc
+    PyObject_dealloc(space, py_obj)
diff --git a/pypy/module/cpyext/include/bufferobject.h b/pypy/module/cpyext/include/bufferobject.h
--- a/pypy/module/cpyext/include/bufferobject.h
+++ b/pypy/module/cpyext/include/bufferobject.h
@@ -9,6 +9,17 @@
 extern "C" {
 #endif
 
+typedef struct {
+	PyObject_HEAD
+	PyObject *b_base;
+	void *b_ptr;
+	Py_ssize_t b_size;
+	Py_ssize_t b_offset;
+	int b_readonly;
+	long b_hash;
+} PyBufferObject;
+
+
 PyAPI_DATA(PyTypeObject) PyBuffer_Type;
 
 #define PyBuffer_Check(op) (((PyObject*)(op))->ob_type == &PyBuffer_Type)
diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -234,7 +234,7 @@
 	writebufferproc bf_getwritebuffer;
 	segcountproc bf_getsegcount;
 	charbufferproc bf_getcharbuffer;
-  getbufferproc bf_getbuffer;
+	getbufferproc bf_getbuffer;
 	releasebufferproc bf_releasebuffer;
 } PyBufferProcs;
 
diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -58,6 +58,7 @@
 class W_PyCFunctionObject(Wrappable):
     def __init__(self, space, ml, w_self, w_module=None):
         self.ml = ml
+        self.name = rffi.charp2str(self.ml.c_ml_name)
         self.w_self = w_self
         self.w_module = w_module
 
@@ -69,7 +70,7 @@
         flags &= ~(METH_CLASS | METH_STATIC | METH_COEXIST)
         if space.is_true(w_kw) and not flags & METH_KEYWORDS:
             raise OperationError(space.w_TypeError, space.wrap(
-                rffi.charp2str(self.ml.c_ml_name) + "() takes no keyword arguments"))
+                self.name + "() takes no keyword arguments"))
 
         func = rffi.cast(PyCFunction, self.ml.c_ml_meth)
         length = space.int_w(space.len(w_args))
@@ -80,13 +81,12 @@
             if length == 0:
                 return generic_cpy_call(space, func, w_self, None)
             raise OperationError(space.w_TypeError, space.wrap(
-                rffi.charp2str(self.ml.c_ml_name) + "() takes no arguments"))
+                self.name + "() takes no arguments"))
         elif flags & METH_O:
             if length != 1:
                 raise OperationError(space.w_TypeError,
                         space.wrap("%s() takes exactly one argument (%d given)" %  (
-                        rffi.charp2str(self.ml.c_ml_name), 
-                        length)))
+                        self.name, length)))
             w_arg = space.getitem(w_args, space.wrap(0))
             return generic_cpy_call(space, func, w_self, w_arg)
         elif flags & METH_VARARGS:
@@ -199,6 +199,7 @@
     __call__ = interp2app(cfunction_descr_call),
     __doc__ = GetSetProperty(W_PyCFunctionObject.get_doc),
     __module__ = interp_attrproperty_w('w_module', cls=W_PyCFunctionObject),
+    __name__ = interp_attrproperty('name', cls=W_PyCFunctionObject),
     )
 W_PyCFunctionObject.typedef.acceptable_as_base_class = False
 
diff --git a/pypy/module/cpyext/src/bufferobject.c b/pypy/module/cpyext/src/bufferobject.c
--- a/pypy/module/cpyext/src/bufferobject.c
+++ b/pypy/module/cpyext/src/bufferobject.c
@@ -4,17 +4,6 @@
 #include "Python.h"
 
 
-typedef struct {
-	PyObject_HEAD
-	PyObject *b_base;
-	void *b_ptr;
-	Py_ssize_t b_size;
-	Py_ssize_t b_offset;
-	int b_readonly;
-	long b_hash;
-} PyBufferObject;
-
-
 enum buffer_t {
     READ_BUFFER,
     WRITE_BUFFER,
diff --git a/pypy/module/cpyext/src/getargs.c b/pypy/module/cpyext/src/getargs.c
--- a/pypy/module/cpyext/src/getargs.c
+++ b/pypy/module/cpyext/src/getargs.c
@@ -777,18 +777,14 @@
 			Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *);
 
 			if (PyString_Check(arg)) {
+                            fflush(stdout);
 				PyBuffer_FillInfo(p, arg,
 						  PyString_AS_STRING(arg), PyString_GET_SIZE(arg),
 						  1, 0);
-			} else {
-                            PyErr_SetString(
-                                PyExc_NotImplementedError,
-                                "s* not implemented for non-string values");
-                            return NULL;
-                        }
-#if 0
+			}
 #ifdef Py_USING_UNICODE
 			else if (PyUnicode_Check(arg)) {
+#if 0
 				uarg = UNICODE_DEFAULT_ENCODING(arg);
 				if (uarg == NULL)
 					return converterr(CONV_UNICODE,
@@ -796,6 +792,9 @@
 				PyBuffer_FillInfo(p, arg,
 						  PyString_AS_STRING(uarg), PyString_GET_SIZE(uarg),
 						  1, 0);
+#else
+                                return converterr("string or buffer", arg, msgbuf, bufsize);
+#endif
 			}
 #endif
 			else { /* any buffer-like object */
@@ -803,7 +802,6 @@
 				if (getbuffer(arg, p, &buf) < 0)
 					return converterr(buf, arg, msgbuf, bufsize);
 			}
-#endif
 			if (addcleanup(p, freelist, cleanup_buffer)) {
 				return converterr(
 					"(cleanup problem)",
@@ -1342,7 +1340,6 @@
 	return count;
 }
 
-#if 0 //YYY
 static int
 getbuffer(PyObject *arg, Py_buffer *view, char **errmsg)
 {
@@ -1373,7 +1370,6 @@
 	PyBuffer_FillInfo(view, NULL, buf, count, 1, 0);
 	return 0;
 }
-#endif
 
 /* Support for keyword arguments donated by
    Geoff Philbrick <philbric at delphi.hks.com> */
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -1,5 +1,5 @@
 from pypy.module.cpyext.api import (
-    cpython_api, PyObject, PyObjectP, CANNOT_FAIL
+    cpython_api, PyObject, PyObjectP, CANNOT_FAIL, Py_buffer
     )
 from pypy.module.cpyext.complexobject import Py_complex_ptr as Py_complex
 from pypy.rpython.lltypesystem import rffi, lltype
@@ -10,7 +10,6 @@
 PyMethodDef = rffi.VOIDP
 PyGetSetDef = rffi.VOIDP
 PyMemberDef = rffi.VOIDP
-Py_buffer = rffi.VOIDP
 va_list = rffi.VOIDP
 PyDateTime_Date = rffi.VOIDP
 PyDateTime_DateTime = rffi.VOIDP
@@ -178,13 +177,6 @@
     ~Py_buffer.format."""
     raise NotImplementedError
 
- at cpython_api([Py_buffer, lltype.Char], rffi.INT_real, error=CANNOT_FAIL)
-def PyBuffer_IsContiguous(space, view, fortran):
-    """Return 1 if the memory defined by the view is C-style (fortran is
-    'C') or Fortran-style (fortran is 'F') contiguous or either one
-    (fortran is 'A').  Return 0 otherwise."""
-    raise NotImplementedError
-
 @cpython_api([rffi.INT_real, Py_ssize_t, Py_ssize_t, Py_ssize_t, lltype.Char], lltype.Void)
 def PyBuffer_FillContiguousStrides(space, ndim, shape, strides, itemsize, fortran):
     """Fill the strides array with byte-strides of a contiguous (C-style if
diff --git a/pypy/module/cpyext/test/test_getargs.py b/pypy/module/cpyext/test/test_getargs.py
--- a/pypy/module/cpyext/test/test_getargs.py
+++ b/pypy/module/cpyext/test/test_getargs.py
@@ -129,6 +129,21 @@
         assert 'foo\0bar\0baz' == pybuffer('foo\0bar\0baz')
 
 
+    def test_pyarg_parse_string_old_buffer(self):
+        pybuffer = self.import_parser(
+            '''
+            Py_buffer buf;
+            PyObject *result;
+            if (!PyArg_ParseTuple(args, "s*", &buf)) {
+                return NULL;
+            }
+            result = PyString_FromStringAndSize(buf.buf, buf.len);
+            PyBuffer_Release(&buf);
+            return result;
+            ''')
+        assert 'foo\0bar\0baz' == pybuffer(buffer('foo\0bar\0baz'))
+
+
     def test_pyarg_parse_charbuf_and_length(self):
         """
         The `t#` format specifier can be used to parse a read-only 8-bit
diff --git a/pypy/module/cpyext/test/test_methodobject.py b/pypy/module/cpyext/test/test_methodobject.py
--- a/pypy/module/cpyext/test/test_methodobject.py
+++ b/pypy/module/cpyext/test/test_methodobject.py
@@ -63,6 +63,7 @@
              ),
             ])
         assert mod.getarg_O(1) == 1
+        assert mod.getarg_O.__name__ == "getarg_O"
         raises(TypeError, mod.getarg_O)
         raises(TypeError, mod.getarg_O, 1, 1)
 
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -28,6 +28,7 @@
     PyNumberMethods, PyMappingMethods, PySequenceMethods, PyBufferProcs)
 from pypy.module.cpyext.slotdefs import (
     slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
+from pypy.interpreter.buffer import Buffer
 from pypy.interpreter.error import OperationError
 from pypy.rlib.rstring import rsplit
 from pypy.rlib.objectmodel import specialize
@@ -418,8 +419,21 @@
     Py_DecRef(space, pyref)
     return space.len_w(w_str)
 
+ at cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
+             external=False, error=-1)
+def buf_getreadbuffer(space, pyref, segment, ref):
+    from pypy.module.cpyext.bufferobject import PyBufferObject
+    if segment != 0:
+        raise OperationError(space.w_SystemError, space.wrap
+                             ("accessing non-existent string segment"))
+    py_buf = rffi.cast(PyBufferObject, pyref)
+    ref[0] = py_buf.c_b_ptr
+    #Py_DecRef(space, pyref)
+    return py_buf.c_b_size
+
 def setup_string_buffer_procs(space, pto):
     c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
+    lltype.render_immortal(c_buf)
     c_buf.c_bf_getsegcount = llhelper(str_segcount.api_func.functype,
                                       str_segcount.api_func.get_wrapper(space))
     c_buf.c_bf_getreadbuffer = llhelper(str_getreadbuffer.api_func.functype,
@@ -429,6 +443,15 @@
     pto.c_tp_as_buffer = c_buf
     pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
 
+def setup_buffer_buffer_procs(space, pto):
+    c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
+    lltype.render_immortal(c_buf)
+    c_buf.c_bf_getsegcount = llhelper(str_segcount.api_func.functype,
+                                      str_segcount.api_func.get_wrapper(space))
+    c_buf.c_bf_getreadbuffer = llhelper(buf_getreadbuffer.api_func.functype,
+                                 buf_getreadbuffer.api_func.get_wrapper(space))
+    pto.c_tp_as_buffer = c_buf
+
 @cpython_api([PyObject], lltype.Void, external=False)
 def type_dealloc(space, obj):
     from pypy.module.cpyext.object import PyObject_dealloc
@@ -484,6 +507,8 @@
     # buffer protocol
     if space.is_w(w_type, space.w_str):
         setup_string_buffer_procs(space, pto)
+    if space.is_w(w_type, space.gettypefor(Buffer)):
+        setup_buffer_buffer_procs(space, pto)
 
     pto.c_tp_free = llhelper(PyObject_Del.api_func.functype,
             PyObject_Del.api_func.get_wrapper(space))
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -21,7 +21,6 @@
     _immutable_fields_ = ["itemtype", "num", "kind"]
 
     def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[]):
-        self.signature = signature.BaseSignature()
         self.itemtype = itemtype
         self.num = num
         self.kind = kind
@@ -228,4 +227,4 @@
         )
 
 def get_dtype_cache(space):
-    return space.fromcache(DtypeCache)
\ No newline at end of file
+    return space.fromcache(DtypeCache)
diff --git a/pypy/module/micronumpy/interp_extras.py b/pypy/module/micronumpy/interp_extras.py
--- a/pypy/module/micronumpy/interp_extras.py
+++ b/pypy/module/micronumpy/interp_extras.py
@@ -4,4 +4,4 @@
 
 @unwrap_spec(array=BaseArray)
 def debug_repr(space, array):
-    return space.wrap(array.debug_repr())
+    return space.wrap(array.find_sig().debug_repr())
diff --git a/pypy/module/micronumpy/interp_iter.py b/pypy/module/micronumpy/interp_iter.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/interp_iter.py
@@ -0,0 +1,128 @@
+
+from pypy.rlib import jit
+from pypy.rlib.objectmodel import instantiate
+from pypy.module.micronumpy.strides import calculate_broadcast_strides
+
+# Iterators for arrays
+# --------------------
+# all those iterators with the exception of BroadcastIterator iterate over the
+# entire array in C order (the last index changes the fastest). This will
+# yield all elements. Views iterate over indices and look towards strides and
+# backstrides to find the correct position. Notably the offset between
+# x[..., i + 1] and x[..., i] will be strides[-1]. Offset between
+# x[..., k + 1, 0] and x[..., k, i_max] will be backstrides[-2] etc.
+
+# BroadcastIterator works like that, but for indexes that don't change source
+# in the original array, strides[i] == backstrides[i] == 0
+
+class BaseIterator(object):
+    def next(self, shapelen):
+        raise NotImplementedError
+
+    def done(self):
+        raise NotImplementedError
+
+class ArrayIterator(BaseIterator):
+    def __init__(self, size):
+        self.offset = 0
+        self.size = size
+
+    def next(self, shapelen):
+        arr = instantiate(ArrayIterator)
+        arr.size = self.size
+        arr.offset = self.offset + 1
+        return arr
+
+    def done(self):
+        return self.offset >= self.size
+
+class OneDimIterator(BaseIterator):
+    def __init__(self, start, step, stop):
+        self.offset = start
+        self.step = step
+        self.size = stop * step + start
+
+    def next(self, shapelen):
+        arr = instantiate(OneDimIterator)
+        arr.size = self.size
+        arr.step = self.step
+        arr.offset = self.offset + self.step
+        return arr
+
+    def done(self):
+        return self.offset == self.size
+
+def view_iter_from_arr(arr):
+    return ViewIterator(arr.start, arr.strides, arr.backstrides, arr.shape)
+
+class ViewIterator(BaseIterator):
+    def __init__(self, start, strides, backstrides, shape, res_shape=None):
+        self.offset  = start
+        self._done   = False
+        if res_shape is not None and res_shape != shape:
+            r = calculate_broadcast_strides(strides, backstrides,
+                                            shape, res_shape)
+            self.strides, self.backstrides = r
+            self.res_shape = res_shape
+        else:
+            self.strides = strides
+            self.backstrides = backstrides
+            self.res_shape = shape
+        self.indices = [0] * len(self.res_shape)
+
+    @jit.unroll_safe
+    def next(self, shapelen):
+        offset = self.offset
+        indices = [0] * shapelen
+        for i in range(shapelen):
+            indices[i] = self.indices[i]
+        done = False
+        for i in range(shapelen - 1, -1, -1):
+            if indices[i] < self.res_shape[i] - 1:
+                indices[i] += 1
+                offset += self.strides[i]
+                break
+            else:
+                indices[i] = 0
+                offset -= self.backstrides[i]
+        else:
+            done = True
+        res = instantiate(ViewIterator)
+        res.offset = offset
+        res.indices = indices
+        res.strides = self.strides
+        res.backstrides = self.backstrides
+        res.res_shape = self.res_shape
+        res._done = done
+        return res
+
+    def done(self):
+        return self._done
+
+class ConstantIterator(BaseIterator):
+    def next(self, shapelen):
+        return self
+
+# ------ other iterators that are not part of the computation frame ----------
+
+class AxisIterator(object):
+    """ This object will return offsets of each start of the last stride
+    """
+    def __init__(self, arr):
+        self.arr = arr
+        self.indices = [0] * (len(arr.shape) - 1)
+        self.done = False
+        self.offset = arr.start
+
+    def next(self):
+        for i in range(len(self.arr.shape) - 2, -1, -1):
+            if self.indices[i] < self.arr.shape[i] - 1:
+                self.indices[i] += 1
+                self.offset += self.arr.strides[i]
+                break
+            else:
+                self.indices[i] = 0
+                self.offset -= self.arr.backstrides[i]
+        else:
+            self.done = True
+        
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -3,28 +3,33 @@
 from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.module.micronumpy import interp_ufuncs, interp_dtype, signature
+from pypy.module.micronumpy.strides import calculate_slice_strides
 from pypy.rlib import jit
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.rlib.rstring import StringBuilder
-from pypy.rlib.objectmodel import instantiate
-
+from pypy.module.micronumpy.interp_iter import ArrayIterator,\
+     view_iter_from_arr, OneDimIterator, AxisIterator
 
 numpy_driver = jit.JitDriver(
-    greens=['shapelen', 'signature'],
-    reds=['result_size', 'i', 'ri', 'self', 'result']
+    greens=['shapelen', 'sig'],
+    virtualizables=['frame'],
+    reds=['result_size', 'frame', 'ri', 'self', 'result']
 )
 all_driver = jit.JitDriver(
-    greens=['shapelen', 'signature'],
-    reds=['i', 'self', 'dtype']
+    greens=['shapelen', 'sig'],
+    virtualizables=['frame'],
+    reds=['frame', 'self', 'dtype']
 )
 any_driver = jit.JitDriver(
-    greens=['shapelen', 'signature'],
-    reds=['i', 'self', 'dtype']
+    greens=['shapelen', 'sig'],
+    virtualizables=['frame'],
+    reds=['frame', 'self', 'dtype']
 )
 slice_driver = jit.JitDriver(
-    greens=['shapelen', 'signature'],
-    reds=['self', 'source', 'source_iter', 'res_iter']
+    greens=['shapelen', 'sig'],
+    virtualizables=['frame'],
+    reds=['self', 'frame', 'source', 'res_iter']
 )
 
 def _find_shape_and_elems(space, w_iterable):
@@ -198,231 +203,17 @@
                 n_old_elems_to_use *= old_shape[oldI]
     return new_strides
 
-# Iterators for arrays
-# --------------------
-# all those iterators with the exception of BroadcastIterator iterate over the
-# entire array in C order (the last index changes the fastest). This will
-# yield all elements. Views iterate over indices and look towards strides and
-# backstrides to find the correct position. Notably the offset between
-# x[..., i + 1] and x[..., i] will be strides[-1]. Offset between
-# x[..., k + 1, 0] and x[..., k, i_max] will be backstrides[-2] etc.
+class BaseArray(Wrappable):
+    _attrs_ = ["invalidates", "shape", 'size']
 
-# BroadcastIterator works like that, but for indexes that don't change source
-# in the original array, strides[i] == backstrides[i] == 0
-
-class BaseIterator(object):
-    def next(self, shapelen):
-        raise NotImplementedError
-
-    def done(self):
-        raise NotImplementedError
-
-    def get_offset(self):
-        raise NotImplementedError
-
-class ArrayIterator(BaseIterator):
-    def __init__(self, size):
-        self.offset = 0
-        self.size = size
-
-    def next(self, shapelen):
-        arr = instantiate(ArrayIterator)
-        arr.size = self.size
-        arr.offset = self.offset + 1
-        return arr
-
-    def done(self):
-        return self.offset >= self.size
-
-    def get_offset(self):
-        return self.offset
-
-class OneDimIterator(BaseIterator):
-    def __init__(self, start, step, stop):
-        self.offset = start
-        self.step = step
-        self.size = stop * step + start
-
-    def next(self, shapelen):
-        arr = instantiate(OneDimIterator)
-        arr.size = self.size
-        arr.step = self.step
-        arr.offset = self.offset + self.step
-        return arr
-
-    def done(self):
-        return self.offset == self.size
-
-    def get_offset(self):
-        return self.offset
-
-class ViewIterator(BaseIterator):
-    def __init__(self, arr):
-        self.indices = [0] * len(arr.shape)
-        self.offset  = arr.start
-        self.arr     = arr
-        self._done   = False
-
-    @jit.unroll_safe
-    def next(self, shapelen):
-        offset = self.offset
-        indices = [0] * shapelen
-        for i in range(shapelen):
-            indices[i] = self.indices[i]
-        done = False
-        for i in range(shapelen - 1, -1, -1):
-            if indices[i] < self.arr.shape[i] - 1:
-                indices[i] += 1
-                offset += self.arr.strides[i]
-                break
-            else:
-                indices[i] = 0
-                offset -= self.arr.backstrides[i]
-        else:
-            done = True
-        res = instantiate(ViewIterator)
-        res.offset = offset
-        res.indices = indices
-        res.arr = self.arr
-        res._done = done
-        return res
-
-    def done(self):
-        return self._done
-
-    def get_offset(self):
-        return self.offset
-
-class BroadcastIterator(BaseIterator):
-    '''Like a view iterator, but will repeatedly access values
-       for all iterations across a res_shape, folding the offset
-       using mod() arithmetic
-    '''
-    def __init__(self, arr, res_shape):
-        self.indices = [0] * len(res_shape)
-        self.offset  = arr.start
-        #strides are 0 where original shape==1
-        self.strides = []
-        self.backstrides = []
-        for i in range(len(arr.shape)):
-            if arr.shape[i] == 1:
-                self.strides.append(0)
-                self.backstrides.append(0)
-            else:
-                self.strides.append(arr.strides[i])
-                self.backstrides.append(arr.backstrides[i])
-        self.res_shape = res_shape
-        self.strides = [0] * (len(res_shape) - len(arr.shape)) + self.strides
-        self.backstrides = [0] * (len(res_shape) - len(arr.shape)) + self.backstrides
-        self._done = False
-
-    @jit.unroll_safe
-    def next(self, shapelen):
-        offset = self.offset
-        indices = [0] * shapelen
-        _done = False
-        for i in range(shapelen):
-            indices[i] = self.indices[i]
-        for i in range(shapelen - 1, -1, -1):
-            if indices[i] < self.res_shape[i] - 1:
-                indices[i] += 1
-                offset += self.strides[i]
-                break
-            else:
-                indices[i] = 0
-                offset -= self.backstrides[i]
-        else:
-            _done = True
-        res = instantiate(BroadcastIterator)
-        res.indices = indices
-        res.offset = offset
-        res._done = _done
-        res.strides = self.strides
-        res.backstrides = self.backstrides
-        res.res_shape = self.res_shape
-        return res
-
-    def done(self):
-        return self._done
-
-    def get_offset(self):
-        return self.offset
-
-class Call2Iterator(BaseIterator):
-    def __init__(self, left, right):
-        self.left = left
-        self.right = right
-
-    def next(self, shapelen):
-        return Call2Iterator(self.left.next(shapelen),
-                             self.right.next(shapelen))
-
-    def done(self):
-        if isinstance(self.left, ConstantIterator):
-            return self.right.done()
-        return self.left.done()
-
-    def get_offset(self):
-        if isinstance(self.left, ConstantIterator):
-            return self.right.get_offset()
-        return self.left.get_offset()
-
-class Call1Iterator(BaseIterator):
-    def __init__(self, child):
-        self.child = child
-
-    def next(self, shapelen):
-        return Call1Iterator(self.child.next(shapelen))
-
-    def done(self):
-        return self.child.done()
-
-    def get_offset(self):
-        return self.child.get_offset()
-
-class ConstantIterator(BaseIterator):
-    def next(self, shapelen):
-        return self
-
-    def done(self):
-        return False
-
-    def get_offset(self):
-        return 0
-
-
-class BaseArray(Wrappable):
-    _attrs_ = ["invalidates", "signature", "shape", "strides", "backstrides",
-               "start", 'order']
-
-    _immutable_fields_ = ['start', "order"]
+    _immutable_fields_ = []
 
     strides = None
     start = 0
 
-    def __init__(self, shape, order):
+    def __init__(self, shape):
         self.invalidates = []
         self.shape = shape
-        self.order = order
-        if self.strides is None:
-            self.calc_strides(shape)
-
-    def calc_strides(self, shape):
-        strides = []
-        backstrides = []
-        s = 1
-        shape_rev = shape[:]
-        if self.order == 'C':
-            shape_rev.reverse()
-        for sh in shape_rev:
-            strides.append(s)
-            backstrides.append(s * (sh - 1))
-            s *= sh
-        if self.order == 'C':
-            strides.reverse()
-            backstrides.reverse()
-        self.strides = strides[:]
-        self.backstrides = backstrides[:]
 
     def invalidated(self):
         if self.invalidates:
@@ -499,33 +290,34 @@
 
     def _reduce_argmax_argmin_impl(op_name):
         reduce_driver = jit.JitDriver(
-            greens=['shapelen', 'signature'],
-            reds=['result', 'idx', 'i', 'self', 'cur_best', 'dtype']
+            greens=['shapelen', 'sig'],
+            reds=['result', 'idx', 'frame', 'self', 'cur_best', 'dtype']
         )
         def loop(self):
-            i = self.start_iter()
-            cur_best = self.eval(i)
+            sig = self.find_sig()
+            frame = sig.create_frame(self)
+            cur_best = sig.eval(frame, self)
             shapelen = len(self.shape)
-            i = i.next(shapelen)
+            frame.next(shapelen)
             dtype = self.find_dtype()
             result = 0
             idx = 1
-            while not i.done():
-                reduce_driver.jit_merge_point(signature=self.signature,
+            while not frame.done():
+                reduce_driver.jit_merge_point(sig=sig,
                                               shapelen=shapelen,
                                               self=self, dtype=dtype,
-                                              i=i, result=result, idx=idx,
+                                              frame=frame, result=result,
+                                              idx=idx,
                                               cur_best=cur_best)
-                new_best = getattr(dtype.itemtype, op_name)(cur_best, self.eval(i))
+                new_best = getattr(dtype.itemtype, op_name)(cur_best, sig.eval(frame, self))
                 if dtype.itemtype.ne(new_best, cur_best):
                     result = idx
                     cur_best = new_best
-                i = i.next(shapelen)
+                frame.next(shapelen)
                 idx += 1
             return result
         def impl(self, space):
-            size = self.find_size()
-            if size == 0:
+            if self.size == 0:
                 raise OperationError(space.w_ValueError,
                     space.wrap("Can't call %s on zero-size arrays" % op_name))
             return space.wrap(loop(self))
@@ -533,15 +325,16 @@
 
     def _all(self):
         dtype = self.find_dtype()
-        i = self.start_iter()
+        sig = self.find_sig()
+        frame = sig.create_frame(self)
         shapelen = len(self.shape)
-        while not i.done():
-            all_driver.jit_merge_point(signature=self.signature,
+        while not frame.done():
+            all_driver.jit_merge_point(sig=sig,
                                        shapelen=shapelen, self=self,
-                                       dtype=dtype, i=i)
-            if not dtype.itemtype.bool(self.eval(i)):
+                                       dtype=dtype, frame=frame)
+            if not dtype.itemtype.bool(sig.eval(frame, self)):
                 return False
-            i = i.next(shapelen)
+            frame.next(shapelen)
         return True
 
     def descr_all(self, space):
@@ -549,15 +342,16 @@
 
     def _any(self):
         dtype = self.find_dtype()
-        i = self.start_iter()
+        sig = self.find_sig()
+        frame = sig.create_frame(self)
         shapelen = len(self.shape)
-        while not i.done():
-            any_driver.jit_merge_point(signature=self.signature,
+        while not frame.done():
+            any_driver.jit_merge_point(sig=sig, frame=frame,
                                        shapelen=shapelen, self=self,
-                                       dtype=dtype, i=i)
-            if dtype.itemtype.bool(self.eval(i)):
+                                       dtype=dtype)
+            if dtype.itemtype.bool(sig.eval(frame, self)):
                 return True
-            i = i.next(shapelen)
+            frame.next(shapelen)
         return False
 
     def descr_any(self, space):
@@ -586,26 +380,33 @@
         return space.newtuple([space.wrap(i) for i in self.shape])
 
     def descr_set_shape(self, space, w_iterable):
-        concrete = self.get_concrete()
         new_shape = get_shape_from_iterable(space,
-                            concrete.find_size(), w_iterable)
-        concrete.setshape(space, new_shape)
+                            self.size, w_iterable)
+        if isinstance(self, Scalar):
+            return
+        self.get_concrete().setshape(space, new_shape)
 
     def descr_get_size(self, space):
-        return space.wrap(self.find_size())
+        return space.wrap(self.size)
 
     def descr_copy(self, space):
-        return self.get_concrete().copy()
+        return self.copy(space)
+
+    def copy(self, space):
+        return self.get_concrete().copy(space)
 
     def descr_len(self, space):
-        return self.get_concrete().descr_len(space)
+        if len(self.shape):
+            return space.wrap(self.shape[0])
+        raise OperationError(space.w_TypeError, space.wrap(
+            "len() of unsized object"))
 
     def descr_repr(self, space):
         res = StringBuilder()
         res.append("array(")
         concrete = self.get_concrete()
         dtype = concrete.find_dtype()
-        if not concrete.find_size():
+        if not concrete.size:
             res.append('[]')
             if len(self.shape) > 1:
                 # An empty slice reports its shape
@@ -617,18 +418,423 @@
             concrete.to_str(space, 1, res, indent='       ')
         if (dtype is not interp_dtype.get_dtype_cache(space).w_float64dtype and
             dtype is not interp_dtype.get_dtype_cache(space).w_int64dtype) or \
-            not self.find_size():
+            not self.size:
             res.append(", dtype=" + dtype.name)
         res.append(")")
         return space.wrap(res.build())
 
+    def descr_str(self, space):
+        ret = StringBuilder()
+        concrete = self.get_concrete_or_scalar()
+        concrete.to_str(space, 0, ret, ' ')
+        return space.wrap(ret.build())
+
+    @jit.unroll_safe
+    def _single_item_result(self, space, w_idx):
+        """ The result of getitem/setitem is a single item if w_idx
+        is a list of scalars that match the size of shape
+        """
+        shape_len = len(self.shape)
+        if shape_len == 0:
+            raise OperationError(space.w_IndexError, space.wrap(
+                "0-d arrays can't be indexed"))
+        if shape_len == 1:
+            if space.isinstance_w(w_idx, space.w_int):
+                return True
+            if space.isinstance_w(w_idx, space.w_slice):
+                return False
+        elif (space.isinstance_w(w_idx, space.w_slice) or
+              space.isinstance_w(w_idx, space.w_int)):
+            return False
+        lgt = space.len_w(w_idx)
+        if lgt > shape_len:
+            raise OperationError(space.w_IndexError,
+                                 space.wrap("invalid index"))
+        if lgt < shape_len:
+            return False
+        for w_item in space.fixedview(w_idx):
+            if space.isinstance_w(w_item, space.w_slice):
+                return False
+        return True
+
+    @jit.unroll_safe
+    def _prepare_slice_args(self, space, w_idx):
+        if (space.isinstance_w(w_idx, space.w_int) or
+            space.isinstance_w(w_idx, space.w_slice)):
+            return [space.decode_index4(w_idx, self.shape[0])]
+        return [space.decode_index4(w_item, self.shape[i]) for i, w_item in
+                enumerate(space.fixedview(w_idx))]
+
+    def descr_getitem(self, space, w_idx):
+        if self._single_item_result(space, w_idx):
+            concrete = self.get_concrete()
+            item = concrete._index_of_single_item(space, w_idx)
+            return concrete.getitem(item)
+        chunks = self._prepare_slice_args(space, w_idx)
+        return space.wrap(self.create_slice(chunks))
+
+    def descr_setitem(self, space, w_idx, w_value):
+        self.invalidated()
+        if self._single_item_result(space, w_idx):
+            concrete = self.get_concrete()
+            item = concrete._index_of_single_item(space, w_idx)
+            dtype = concrete.find_dtype()
+            concrete.setitem(item, dtype.coerce(space, w_value))
+            return
+        if not isinstance(w_value, BaseArray):
+            w_value = convert_to_array(space, w_value)
+        chunks = self._prepare_slice_args(space, w_idx)
+        view = self.create_slice(chunks).get_concrete()
+        view.setslice(space, w_value)
+
+    @jit.unroll_safe
+    def create_slice(self, chunks):
+        shape = []
+        i = -1
+        for i, (start_, stop, step, lgt) in enumerate(chunks):
+            if step != 0:
+                shape.append(lgt)
+        s = i + 1
+        assert s >= 0
+        shape += self.shape[s:]
+        if not isinstance(self, ConcreteArray):
+            return VirtualSlice(self, chunks, shape)
+        r = calculate_slice_strides(self.shape, self.start, self.strides,
+                                    self.backstrides, chunks)
+        _, start, strides, backstrides = r
+        return W_NDimSlice(start, strides[:], backstrides[:],
+                           shape[:], self)
+
+    def descr_reshape(self, space, args_w):
+        """reshape(...)
+        a.reshape(shape)
+
+        Returns an array containing the same data with a new shape.
+
+        Refer to `numpypy.reshape` for full documentation.
+
+        See Also
+        --------
+        numpypy.reshape : equivalent function
+        """
+        if len(args_w) == 1:
+            w_shape = args_w[0]
+        else:
+            w_shape = space.newtuple(args_w)
+        concrete = self.get_concrete()
+        new_shape = get_shape_from_iterable(space, concrete.size, w_shape)
+        # Since we got to here, prod(new_shape) == self.size
+        new_strides = calc_new_strides(new_shape,
+                                       concrete.shape, concrete.strides)
+        if new_strides:
+            # We can create a view, strides somehow match up.
+            ndims = len(new_shape)
+            new_backstrides = [0] * ndims
+            for nd in range(ndims):
+                new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
+            arr = W_NDimSlice(concrete.start, new_strides, new_backstrides,
+                              new_shape, self)
+        else:
+            # Create copy with contiguous data
+            arr = concrete.copy(space)
+            arr.setshape(space, new_shape)
+        return arr
+
+    def descr_tolist(self, space):
+        if len(self.shape) == 0:
+            assert isinstance(self, Scalar)
+            return self.value.descr_tolist(space)
+        w_result = space.newlist([])
+        for i in range(self.shape[0]):
+            space.call_method(w_result, "append",
+                space.call_method(self.descr_getitem(space, space.wrap(i)), "tolist")
+            )
+        return w_result
+
+    def descr_mean(self, space):
+        return space.div(self.descr_sum(space), space.wrap(self.size))
+
+    def descr_nonzero(self, space):
+        if self.size > 1:
+            raise OperationError(space.w_ValueError, space.wrap(
+                "The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()"))
+        concr = self.get_concrete_or_scalar()
+        sig = concr.find_sig()
+        frame = sig.create_frame(self)
+        return space.wrap(space.is_true(
+            sig.eval(frame, concr)))
+
+    def get_concrete_or_scalar(self):
+        return self.get_concrete()
+
+    def descr_get_transpose(self, space):
+        concrete = self.get_concrete()
+        if len(concrete.shape) < 2:
+            return space.wrap(self)
+        strides = []
+        backstrides = []
+        shape = []
+        for i in range(len(concrete.shape) - 1, -1, -1):
+            strides.append(concrete.strides[i])
+            backstrides.append(concrete.backstrides[i])
+            shape.append(concrete.shape[i])
+        return space.wrap(W_NDimSlice(concrete.start, strides[:],
+                                      backstrides[:], shape[:], concrete))
+
+    def descr_get_flatiter(self, space):
+        return space.wrap(W_FlatIterator(self))
+
+    def getitem(self, item):
+        raise NotImplementedError
+
+    def find_sig(self, res_shape=None):
+        """ find a correct signature for the array
+        """
+        res_shape = res_shape or self.shape
+        return signature.find_sig(self.create_sig(res_shape), self)
+
+    def descr_array_iface(self, space):
+        if not self.shape:
+            raise OperationError(space.w_TypeError,
+                space.wrap("can't get the array data of a 0-d array for now")
+            )
+        concrete = self.get_concrete()
+        storage = concrete.storage
+        addr = rffi.cast(lltype.Signed, storage)
+        w_d = space.newdict()
+        space.setitem_str(w_d, 'data', space.newtuple([space.wrap(addr),
+                                                       space.w_False]))
+        return w_d
+
+    def supports_fast_slicing(self):
+        return False
+
+def convert_to_array(space, w_obj):
+    if isinstance(w_obj, BaseArray):
+        return w_obj
+    elif space.issequence_w(w_obj):
+        # Convert to array.
+        return array(space, w_obj, w_order=None)
+    else:
+        # If it's a scalar
+        dtype = interp_ufuncs.find_dtype_for_scalar(space, w_obj)
+        return scalar_w(space, dtype, w_obj)
+
+def scalar_w(space, dtype, w_obj):
+    return Scalar(dtype, dtype.coerce(space, w_obj))
+
+class Scalar(BaseArray):
+    """
+    Intermediate class representing a literal.
+    """
+    size = 1
+    _attrs_ = ["dtype", "value", "shape"]
+
+    def __init__(self, dtype, value):
+        self.shape = []
+        BaseArray.__init__(self, [])
+        self.dtype = dtype
+        self.value = value
+
+    def find_dtype(self):
+        return self.dtype
+
+    def to_str(self, space, comma, builder, indent=' ', use_ellipsis=False):
+        builder.append(self.dtype.itemtype.str_format(self.value))
+
+    def copy(self, space):
+        return Scalar(self.dtype, self.value)
+
+    def create_sig(self, res_shape):
+        return signature.ScalarSignature(self.dtype)
+
+    def get_concrete_or_scalar(self):
+        return self
+
+
+class VirtualArray(BaseArray):
+    """
+    Class for representing virtual arrays, such as binary ops or ufuncs
+    """
+    def __init__(self, name, shape, res_dtype):
+        BaseArray.__init__(self, shape)
+        self.forced_result = None
+        self.res_dtype = res_dtype
+        self.name = name
+
+    def _del_sources(self):
+        # Function for deleting references to source arrays, to allow garbage-collecting them
+        raise NotImplementedError
+
+    def compute(self):
+        result = W_NDimArray(self.size, self.shape, self.find_dtype())
+        shapelen = len(self.shape)
+        sig = self.find_sig()
+        frame = sig.create_frame(self)
+        ri = ArrayIterator(self.size)
+        while not ri.done():
+            numpy_driver.jit_merge_point(sig=sig,
+                                         shapelen=shapelen,
+                                         result_size=self.size,
+                                         frame=frame,
+                                         ri=ri,
+                                         self=self, result=result)
+            result.dtype.setitem(result.storage, ri.offset,
+                                 sig.eval(frame, self))
+            frame.next(shapelen)
+            ri = ri.next(shapelen)
+        return result
+
+    def force_if_needed(self):
+        if self.forced_result is None:
+            self.forced_result = self.compute()
+            self._del_sources()
+
+    def get_concrete(self):
+        self.force_if_needed()
+        res = self.forced_result
+        assert isinstance(res, ConcreteArray)
+        return res
+
+    def getitem(self, item):
+        return self.get_concrete().getitem(item)
+
+    def setitem(self, item, value):
+        return self.get_concrete().setitem(item, value)
+
+    def find_dtype(self):
+        return self.res_dtype
+
+class VirtualSlice(VirtualArray):
+    def __init__(self, child, chunks, shape):
+        size = 1
+        for sh in shape:
+            size *= sh
+        self.child = child
+        self.chunks = chunks
+        self.size = size
+        VirtualArray.__init__(self, 'slice', shape, child.find_dtype())
+
+    def create_sig(self, res_shape):
+        if self.forced_result is not None:
+            return self.forced_result.create_sig(res_shape)
+        return signature.VirtualSliceSignature(
+            self.child.create_sig(res_shape))
+
+    def force_if_needed(self):
+        if self.forced_result is None:
+            concr = self.child.get_concrete()
+            self.forced_result = concr.create_slice(self.chunks)
+
+    def _del_sources(self):
+        self.child = None
+
+class Call1(VirtualArray):
+    def __init__(self, ufunc, name, shape, res_dtype, values):
+        VirtualArray.__init__(self, name, shape, res_dtype)
+        self.values = values
+        self.size = values.size
+        self.ufunc = ufunc
+
+    def _del_sources(self):
+        self.values = None
+
+    def create_sig(self, res_shape):
+        if self.forced_result is not None:
+            return self.forced_result.create_sig(res_shape)
+        return signature.Call1(self.ufunc, self.name,
+                               self.values.create_sig(res_shape))
+
+class Call2(VirtualArray):
+    """
+    Intermediate class for performing binary operations.
+    """
+    def __init__(self, ufunc, name, shape, calc_dtype, res_dtype, left, right):
+        VirtualArray.__init__(self, name, shape, res_dtype)
+        self.ufunc = ufunc
+        self.left = left
+        self.right = right
+        self.calc_dtype = calc_dtype
+        self.size = 1
+        for s in self.shape:
+            self.size *= s
+
+    def _del_sources(self):
+        self.left = None
+        self.right = None
+
+    def create_sig(self, res_shape):
+        if self.forced_result is not None:
+            return self.forced_result.create_sig(res_shape)
+        return signature.Call2(self.ufunc, self.name, self.calc_dtype,
+                               self.left.create_sig(res_shape),
+                               self.right.create_sig(res_shape))
+
+class ConcreteArray(BaseArray):
+    """ An array that have actual storage, whether owned or not
+    """
+    _immutable_fields_ = ['storage']
+
+    def __init__(self, size, shape, dtype, order='C', parent=None):
+        self.size = size
+        self.parent = parent
+        if parent is not None:
+            self.storage = parent.storage
+        else:
+            self.storage = dtype.malloc(size)
+        self.order = order
+        self.dtype = dtype
+        if self.strides is None:
+            self.calc_strides(shape)
+        BaseArray.__init__(self, shape)
+        if parent is not None:
+            self.invalidates = parent.invalidates
+
+    def get_concrete(self):
+        return self
+
+    def supports_fast_slicing(self):
+        return self.order == 'C' and self.strides[-1] == 1
+
+    def find_dtype(self):
+        return self.dtype
+
+    def getitem(self, item):
+        return self.dtype.getitem(self.storage, item)
+
+    def setitem(self, item, value):
+        self.invalidated()
+        self.dtype.setitem(self.storage, item, value)
+
+    def calc_strides(self, shape):
+        strides = []
+        backstrides = []
+        s = 1
+        shape_rev = shape[:]
+        if self.order == 'C':
+            shape_rev.reverse()
+        for sh in shape_rev:
+            strides.append(s)
+            backstrides.append(s * (sh - 1))
+            s *= sh
+        if self.order == 'C':
+            strides.reverse()
+            backstrides.reverse()
+        self.strides = strides[:]
+        self.backstrides = backstrides[:]
+
+    def array_sig(self, res_shape):
+        if res_shape is not None and self.shape != res_shape:
+            return signature.ViewSignature(self.dtype)
+        return signature.ArraySignature(self.dtype)
+
     def to_str(self, space, comma, builder, indent=' ', use_ellipsis=False):
         '''Modifies builder with a representation of the array/slice
         The items will be seperated by a comma if comma is 1
         Multidimensional arrays/slices will span a number of lines,
         each line will begin with indent.
         '''
-        size = self.find_size()
+        size = self.size
         if size < 1:
             builder.append('[]')
             return
@@ -654,7 +860,7 @@
                             builder.append(indent)
                     # create_slice requires len(chunks) > 1 in order to reduce
                     # shape
-                    view = self.create_slice(space, [(i, 0, 0, 1), (0, self.shape[1], 1, self.shape[1])])
+                    view = self.create_slice([(i, 0, 0, 1), (0, self.shape[1], 1, self.shape[1])]).get_concrete()
                     view.to_str(space, comma, builder, indent=indent + ' ', use_ellipsis=use_ellipsis)
                 builder.append('\n' + indent + '..., ')
                 i = self.shape[0] - 3
@@ -669,7 +875,7 @@
                         builder.append(indent)
                 # create_slice requires len(chunks) > 1 in order to reduce
                 # shape
-                view = self.create_slice(space, [(i, 0, 0, 1), (0, self.shape[1], 1, self.shape[1])])
+                view = self.create_slice([(i, 0, 0, 1), (0, self.shape[1], 1, self.shape[1])]).get_concrete()
                 view.to_str(space, comma, builder, indent=indent + ' ', use_ellipsis=use_ellipsis)
                 i += 1
         elif ndims == 1:
@@ -705,12 +911,6 @@
             builder.append('[')
         builder.append(']')
 
-    def descr_str(self, space):
-        ret = StringBuilder()
-        concrete = self.get_concrete()
-        concrete.to_str(space, 0, ret, ' ')
-        return space.wrap(ret.build())
-
     @jit.unroll_safe
     def _index_of_single_item(self, space, w_idx):
         if space.isinstance_w(w_idx, space.w_int):
@@ -735,456 +935,76 @@
             item += v * self.strides[i]
         return item
 
-    @jit.unroll_safe
-    def _single_item_result(self, space, w_idx):
-        """ The result of getitem/setitem is a single item if w_idx
-        is a list of scalars that match the size of shape
-        """
-        shape_len = len(self.shape)
-        if shape_len == 0:
-            if not space.isinstance_w(w_idx, space.w_int):
-                raise OperationError(space.w_IndexError, space.wrap(
-                    "wrong index"))
-            return True
-        if shape_len == 1:
-            if space.isinstance_w(w_idx, space.w_int):
-                return True
-            if space.isinstance_w(w_idx, space.w_slice):
-                return False
-        elif (space.isinstance_w(w_idx, space.w_slice) or
-              space.isinstance_w(w_idx, space.w_int)):
-            return False
-        lgt = space.len_w(w_idx)
-        if lgt > shape_len:
-            raise OperationError(space.w_IndexError,
-                                 space.wrap("invalid index"))
-        if lgt < shape_len:
-            return False
-        for w_item in space.fixedview(w_idx):
-            if space.isinstance_w(w_item, space.w_slice):
-                return False
-        return True
+    def setslice(self, space, w_value):
+        res_shape = shape_agreement(space, self.shape, w_value.shape)
+        if (res_shape == w_value.shape and self.supports_fast_slicing() and
+            w_value.supports_fast_slicing() and
+            self.dtype is w_value.find_dtype()):
+            self._fast_setslice(space, w_value)
+        else:
+            self._sliceloop(w_value, res_shape)
 
-    @jit.unroll_safe
-    def _prepare_slice_args(self, space, w_idx):
-        if (space.isinstance_w(w_idx, space.w_int) or
-            space.isinstance_w(w_idx, space.w_slice)):
-            return [space.decode_index4(w_idx, self.shape[0])]
-        return [space.decode_index4(w_item, self.shape[i]) for i, w_item in
-                enumerate(space.fixedview(w_idx))]
+    def _fast_setslice(self, space, w_value):
+        assert isinstance(w_value, ConcreteArray)
+        itemsize = self.dtype.itemtype.get_element_size()
+        if len(self.shape) == 1:
+            rffi.c_memcpy(
+                rffi.ptradd(self.storage, self.start * itemsize),
+                rffi.ptradd(w_value.storage, w_value.start * itemsize),
+                self.size * itemsize
+            )
+        else:
+            dest = AxisIterator(self)
+            source = AxisIterator(w_value)
+            while not dest.done:
+                rffi.c_memcpy(
+                    rffi.ptradd(self.storage, dest.offset * itemsize),
+                    rffi.ptradd(w_value.storage, source.offset * itemsize),
+                    self.shape[-1] * itemsize
+                )
+                source.next()
+                dest.next()
 
-    def descr_getitem(self, space, w_idx):
-        if self._single_item_result(space, w_idx):
-            concrete = self.get_concrete()
-            if len(concrete.shape) < 1:
-                raise OperationError(space.w_IndexError, space.wrap(
-                        "0-d arrays can't be indexed"))
-            item = concrete._index_of_single_item(space, w_idx)
-            return concrete.getitem(item)
-        chunks = self._prepare_slice_args(space, w_idx)
-        return space.wrap(self.create_slice(space, chunks))
+    def _sliceloop(self, source, res_shape):
+        sig = source.find_sig(res_shape)
+        frame = sig.create_frame(source, res_shape)
+        res_iter = view_iter_from_arr(self)
+        shapelen = len(res_shape)
+        while not res_iter.done():
+            slice_driver.jit_merge_point(sig=sig,
+                                         frame=frame,
+                                         shapelen=shapelen,
+                                         self=self, source=source,
+                                         res_iter=res_iter)
+            self.setitem(res_iter.offset, sig.eval(frame, source).convert_to(
+                self.find_dtype()))
+            frame.next(shapelen)
+            res_iter = res_iter.next(shapelen)
 
-    def descr_setitem(self, space, w_idx, w_value):
-        self.invalidated()
-        if self._single_item_result(space, w_idx):
-            concrete = self.get_concrete()
-            if len(concrete.shape) < 1:
-                raise OperationError(space.w_IndexError, space.wrap(
-                        "0-d arrays can't be indexed"))
-            item = concrete._index_of_single_item(space, w_idx)
-            dtype = concrete.find_dtype()
-            concrete.setitem(item, dtype.coerce(space, w_value))
-            return
-        if not isinstance(w_value, BaseArray):
-            w_value = convert_to_array(space, w_value)
-        chunks = self._prepare_slice_args(space, w_idx)
-        view = self.create_slice(space, chunks)
-        view.setslice(space, w_value)
+    def copy(self, space):
+        array = W_NDimArray(self.size, self.shape[:], self.dtype, self.order)
+        array.setslice(space, self)
+        return array
 
-    @jit.unroll_safe
-    def create_slice(self, space, chunks):
-        if len(chunks) == 1:
-            start, stop, step, lgt = chunks[0]
-            if step == 0:
-                shape = self.shape[1:]
-                strides = self.strides[1:]
-                backstrides = self.backstrides[1:]
-            else:
-                shape = [lgt] + self.shape[1:]
-                strides = [self.strides[0] * step] + self.strides[1:]
-                backstrides = [(lgt - 1) * self.strides[0] * step] + self.backstrides[1:]
-            start *= self.strides[0]
-            start += self.start
-        else:
-            shape = []
-            strides = []
-            backstrides = []
-            start = self.start
-            i = -1
-            for i, (start_, stop, step, lgt) in enumerate(chunks):
-                if step != 0:
-                    shape.append(lgt)
-                    strides.append(self.strides[i] * step)
-                    backstrides.append(self.strides[i] * (lgt - 1) * step)
-                start += self.strides[i] * start_
-            # add a reminder
-            s = i + 1
-            assert s >= 0
-            shape += self.shape[s:]
-            strides += self.strides[s:]
-            backstrides += self.backstrides[s:]
-        new_sig = signature.Signature.find_sig([
-            W_NDimSlice.signature, self.signature,
-        ])
-        return W_NDimSlice(self, new_sig, start, strides[:], backstrides[:],
-                           shape[:])
 
-    def descr_reshape(self, space, args_w):
-        """reshape(...)
-    a.reshape(shape)
+class ViewArray(ConcreteArray):
+    def create_sig(self, res_shape):
+        return signature.ViewSignature(self.dtype)
 
-    Returns an array containing the same data with a new shape.
 
-    Refer to `numpypy.reshape` for full documentation.
-
-    See Also
-    --------
-    numpypy.reshape : equivalent function
-"""
-        if len(args_w) == 1:
-            w_shape = args_w[0]
-        else:
-            w_shape = space.newtuple(args_w)
-        concrete = self.get_concrete()
-        new_shape = get_shape_from_iterable(space,
-                                            concrete.find_size(), w_shape)
-        # Since we got to here, prod(new_shape) == self.size
-        new_strides = calc_new_strides(new_shape,
-                                       concrete.shape, concrete.strides)
-        if new_strides:
-            # We can create a view, strides somehow match up.
-            new_sig = signature.Signature.find_sig([
-                W_NDimSlice.signature, self.signature
-            ])
-            ndims = len(new_shape)
-            new_backstrides = [0] * ndims
-            for nd in range(ndims):
-                new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
-            arr = W_NDimSlice(self, new_sig, self.start, new_strides,
-                              new_backstrides, new_shape)
-        else:
-            # Create copy with contiguous data
-            arr = concrete.copy()
-            arr.setshape(space, new_shape)
-        return arr
-
-    def descr_tolist(self, space):
-        if len(self.shape) == 0:
-            assert isinstance(self, Scalar)
-            return self.value.descr_tolist(space)
-        w_result = space.newlist([])
-        for i in range(self.shape[0]):
-            space.call_method(w_result, "append",
-                space.call_method(self.descr_getitem(space, space.wrap(i)), "tolist")
-            )
-        return w_result
-
-    def descr_mean(self, space):
-        return space.div(self.descr_sum(space), space.wrap(self.find_size()))
-
-    def descr_nonzero(self, space):
-        if self.find_size() > 1:
-            raise OperationError(space.w_ValueError, space.wrap(
-                "The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()"))
-        return space.wrap(space.is_true(
-            self.get_concrete().eval(self.start_iter(self.shape))
-        ))
-
-    def descr_get_transpose(self, space):
-        concrete = self.get_concrete()
-        if len(concrete.shape) < 2:
-            return space.wrap(self)
-        new_sig = signature.Signature.find_sig([
-            W_NDimSlice.signature, self.signature
-        ])
-        strides = []
-        backstrides = []
-        shape = []
-        for i in range(len(concrete.shape) - 1, -1, -1):
-            strides.append(concrete.strides[i])
-            backstrides.append(concrete.backstrides[i])
-            shape.append(concrete.shape[i])
-        return space.wrap(W_NDimSlice(concrete, new_sig, self.start, strides[:],
-                                      backstrides[:], shape[:]))
-
-    def descr_get_flatiter(self, space):
-        return space.wrap(W_FlatIterator(self))
-
-    def getitem(self, item):
-        raise NotImplementedError
-
-    def start_iter(self, res_shape=None):
-        raise NotImplementedError
-
-    def descr_array_iface(self, space):
-        concrete = self.get_concrete()
-        storage = concrete.get_storage(space)
-        addr = rffi.cast(lltype.Signed, storage)
-        w_d = space.newdict()
-        space.setitem_str(w_d, 'data', space.newtuple([space.wrap(addr),
-                                                       space.w_False]))
-        return w_d
-
-def convert_to_array(space, w_obj):
-    if isinstance(w_obj, BaseArray):
-        return w_obj
-    elif space.issequence_w(w_obj):
-        # Convert to array.
-        return array(space, w_obj, w_order=None)
-    else:
-        # If it's a scalar
-        dtype = interp_ufuncs.find_dtype_for_scalar(space, w_obj)
-        return scalar_w(space, dtype, w_obj)
-
-def scalar_w(space, dtype, w_obj):
-    return Scalar(dtype, dtype.coerce(space, w_obj))
-
-class Scalar(BaseArray):
-    """
-    Intermediate class representing a literal.
-    """
-    signature = signature.BaseSignature()
-
-    _attrs_ = ["dtype", "value", "shape"]
-
-    def __init__(self, dtype, value):
-        self.shape = self.strides = []
-        BaseArray.__init__(self, [], 'C')
-        self.dtype = dtype
-        self.value = value
-
-    def find_size(self):
-        return 1
-
-    def get_concrete(self):
-        return self
-
-    def find_dtype(self):
-        return self.dtype
-
-    def getitem(self, item):
-        raise NotImplementedError
-
-    def eval(self, iter):
-        return self.value
-
-    def start_iter(self, res_shape=None):
-        return ConstantIterator()
-
-    def to_str(self, space, comma, builder, indent=' ', use_ellipsis=False):
-        builder.append(self.dtype.itemtype.str_format(self.value))
-
-    def copy(self):
-        return Scalar(self.dtype, self.value)
-
-    def debug_repr(self):
-        return 'Scalar'
-
-    def setshape(self, space, new_shape):
-        # In order to get here, we already checked that prod(new_shape) == 1,
-        # so in order to have a consistent API, let it go through.
-        pass
-
-    def get_storage(self, space):
-        raise OperationError(space.w_TypeError, space.wrap("Cannot get array interface on scalars in pypy"))
-
-class VirtualArray(BaseArray):
-    """
-    Class for representing virtual arrays, such as binary ops or ufuncs
-    """
-    def __init__(self, signature, shape, res_dtype, order):
-        BaseArray.__init__(self, shape, order)
-        self.forced_result = None
-        self.signature = signature
-        self.res_dtype = res_dtype
-
-    def _del_sources(self):
-        # Function for deleting references to source arrays, to allow garbage-collecting them
-        raise NotImplementedError
-
-    def compute(self):
-        i = 0
-        signature = self.signature
-        result_size = self.find_size()
-        result = W_NDimArray(result_size, self.shape, self.find_dtype())
-        shapelen = len(self.shape)
-        i = self.start_iter()
-        ri = result.start_iter()
-        while not ri.done():
-            numpy_driver.jit_merge_point(signature=signature,
-                                         shapelen=shapelen,
-                                         result_size=result_size, i=i, ri=ri,
-                                         self=self, result=result)
-            result.dtype.setitem(result.storage, ri.offset, self.eval(i))
-            i = i.next(shapelen)
-            ri = ri.next(shapelen)
-        return result
-
-    def force_if_needed(self):
-        if self.forced_result is None:
-            self.forced_result = self.compute()
-            self._del_sources()
-
-    def get_concrete(self):
-        self.force_if_needed()
-        return self.forced_result
-
-    def eval(self, iter):
-        if self.forced_result is not None:
-            return self.forced_result.eval(iter)
-        return self._eval(iter)
-
-    def getitem(self, item):
-        return self.get_concrete().getitem(item)
-
-    def setitem(self, item, value):
-        return self.get_concrete().setitem(item, value)
-
-    def find_size(self):
-        if self.forced_result is not None:
-            # The result has been computed and sources may be unavailable
-            return self.forced_result.find_size()
-        return self._find_size()
-
-    def find_dtype(self):
-        return self.res_dtype
-
-
-class Call1(VirtualArray):
-    def __init__(self, signature, shape, res_dtype, values, order):
-        VirtualArray.__init__(self, signature, shape, res_dtype,
-                              values.order)
-        self.values = values
-
-    def _del_sources(self):
-        self.values = None
-
-    def _find_size(self):
-        return self.values.find_size()
-
-    def _find_dtype(self):
-        return self.res_dtype
-
-    def _eval(self, iter):
-        assert isinstance(iter, Call1Iterator)
-        val = self.values.eval(iter.child).convert_to(self.res_dtype)
-        sig = jit.promote(self.signature)
-        assert isinstance(sig, signature.Signature)
-        call_sig = sig.components[0]
-        assert isinstance(call_sig, signature.Call1)
-        return call_sig.func(self.res_dtype, val)
-
-    def start_iter(self, res_shape=None):
-        if self.forced_result is not None:
-            return self.forced_result.start_iter(res_shape)
-        return Call1Iterator(self.values.start_iter(res_shape))
-
-    def debug_repr(self):
-        sig = self.signature
-        assert isinstance(sig, signature.Signature)
-        call_sig = sig.components[0]
-        assert isinstance(call_sig, signature.Call1)
-        if self.forced_result is not None:
-            return 'Call1(%s, forced=%s)' % (call_sig.name,
-                                             self.forced_result.debug_repr())
-        return 'Call1(%s, %s)' % (call_sig.name,
-                                  self.values.debug_repr())
-
-class Call2(VirtualArray):
-    """
-    Intermediate class for performing binary operations.
-    """
-    def __init__(self, signature, shape, calc_dtype, res_dtype, left, right):
-        # XXX do something if left.order != right.order
-        VirtualArray.__init__(self, signature, shape, res_dtype, left.order)
-        self.left = left
-        self.right = right
-        self.calc_dtype = calc_dtype
-        self.size = 1
-        for s in self.shape:
-            self.size *= s
-
-    def _del_sources(self):
-        self.left = None
-        self.right = None
-
-    def _find_size(self):
-        return self.size
-
-    def start_iter(self, res_shape=None):
-        if self.forced_result is not None:
-            return self.forced_result.start_iter(res_shape)
-        if res_shape is None:
-            res_shape = self.shape  # we still force the shape on children
-        return Call2Iterator(self.left.start_iter(res_shape),
-                             self.right.start_iter(res_shape))
-
-    def _eval(self, iter):
-        assert isinstance(iter, Call2Iterator)
-        lhs = self.left.eval(iter.left).convert_to(self.calc_dtype)
-        rhs = self.right.eval(iter.right).convert_to(self.calc_dtype)
-        sig = jit.promote(self.signature)
-        assert isinstance(sig, signature.Signature)
-        call_sig = sig.components[0]
-        assert isinstance(call_sig, signature.Call2)
-        return call_sig.func(self.calc_dtype, lhs, rhs)
-
-    def debug_repr(self):
-        sig = self.signature
-        assert isinstance(sig, signature.Signature)
-        call_sig = sig.components[0]
-        assert isinstance(call_sig, signature.Call2)
-        if self.forced_result is not None:
-            return 'Call2(%s, forced=%s)' % (call_sig.name,
-                self.forced_result.debug_repr())
-        return 'Call2(%s, %s, %s)' % (call_sig.name,
-            self.left.debug_repr(),
-            self.right.debug_repr())
-
-class ViewArray(BaseArray):
-    """
-    Class for representing views of arrays, they will reflect changes of parent
-    arrays. Example: slices
-    """
-    def __init__(self, parent, signature, strides, backstrides, shape):
+class W_NDimSlice(ViewArray):
+    def __init__(self, start, strides, backstrides, shape, parent):
+        assert isinstance(parent, ConcreteArray)
+        if isinstance(parent, W_NDimSlice):
+            parent = parent.parent
+        size = 1
+        for sh in shape:
+            size *= sh
         self.strides = strides
         self.backstrides = backstrides
-        BaseArray.__init__(self, shape, parent.order)
-        self.signature = signature
-        self.parent = parent
-        self.invalidates = parent.invalidates
-
-    def get_concrete(self):
-        # in fact, ViewArray never gets "concrete" as it never stores data.
-        # This implementation is needed for BaseArray getitem/setitem to work,
-        # can be refactored.
-        self.parent.get_concrete()
-        return self
-
-    def getitem(self, item):
-        return self.parent.getitem(item)
-
-    def eval(self, iter):
-        return self.parent.getitem(iter.get_offset())
-
-    def setitem(self, item, value):
-        # This is currently not possible to be called from anywhere.
-        raise NotImplementedError
-
-    def descr_len(self, space):
-        if self.shape:
-            return space.wrap(self.shape[0])
-        return space.wrap(1)
+        ViewArray.__init__(self, size, shape, parent.dtype, parent.order,
+                               parent)
+        self.start = start
 
     def setshape(self, space, new_shape):
         if len(self.shape) < 1:
@@ -1220,131 +1040,20 @@
         self.backstrides = new_backstrides[:]
         self.shape = new_shape[:]
 
-class W_NDimSlice(ViewArray):
-    signature = signature.BaseSignature()
-
-    def __init__(self, parent, signature, start, strides, backstrides,
-                 shape):
-        if isinstance(parent, W_NDimSlice):
-            parent = parent.parent
-        ViewArray.__init__(self, parent, signature, strides, backstrides, shape)
-        self.start = start
-        self.size = 1
-        for sh in shape:
-            self.size *= sh
-
-    def find_size(self):
-        return self.size
-
-    def find_dtype(self):
-        return self.parent.find_dtype()
-
-    def setslice(self, space, w_value):
-        res_shape = shape_agreement(space, self.shape, w_value.shape)
-        self._sliceloop(w_value, res_shape)
-
-    def _sliceloop(self, source, res_shape):
-        source_iter = source.start_iter(res_shape)
-        res_iter = self.start_iter(res_shape)
-        shapelen = len(res_shape)
-        while not res_iter.done():
-            slice_driver.jit_merge_point(signature=source.signature,
-                                         shapelen=shapelen,
-                                         self=self, source=source,
-                                         res_iter=res_iter,
-                                         source_iter=source_iter)
-            self.setitem(res_iter.offset, source.eval(source_iter).convert_to(
-                self.find_dtype()))
-            source_iter = source_iter.next(shapelen)
-            res_iter = res_iter.next(shapelen)
-
-    def start_iter(self, res_shape=None):
-        if res_shape is not None and res_shape != self.shape:
-            return BroadcastIterator(self, res_shape)
-        if len(self.shape) == 1:
-            return OneDimIterator(self.start, self.strides[0], self.shape[0])
-        return ViewIterator(self)
-
-    def setitem(self, item, value):
-        self.parent.setitem(item, value)
-
-    def debug_repr(self):
-        return 'Slice(%s)' % self.parent.debug_repr()
-
-    def copy(self):
-        array = W_NDimArray(self.size, self.shape[:], self.find_dtype())
-        iter = self.start_iter()
-        a_iter = array.start_iter()
-        while not iter.done():
-            array.setitem(a_iter.offset, self.getitem(iter.offset))
-            iter = iter.next(len(self.shape))
-            a_iter = a_iter.next(len(array.shape))
-        return array
-
-    def get_storage(self, space):
-        return self.parent.get_storage(space)
-
-class W_NDimArray(BaseArray):
+class W_NDimArray(ConcreteArray):
     """ A class representing contiguous array. We know that each iteration
     by say ufunc will increase the data index by one
     """
-    def __init__(self, size, shape, dtype, order='C'):
-        BaseArray.__init__(self, shape, order)
-        self.size = size
-        self.dtype = dtype
-        self.storage = dtype.malloc(size)
-        self.signature = dtype.signature
-
-    def get_concrete(self):
-        return self
-
-    def find_size(self):
-        return self.size
-
-    def find_dtype(self):
-        return self.dtype
-
-    def getitem(self, item):
-        return self.dtype.getitem(self.storage, item)
-
-    def eval(self, iter):
-        return self.dtype.getitem(self.storage, iter.get_offset())
-
-    def copy(self):
-        array = W_NDimArray(self.size, self.shape[:], self.dtype, self.order)
-        rffi.c_memcpy(
-            array.storage,
-            self.storage,
-            self.size * self.dtype.itemtype.get_element_size()
-        )
-        return array
-
-    def descr_len(self, space):
-        if len(self.shape):
-            return space.wrap(self.shape[0])
-        raise OperationError(space.w_TypeError, space.wrap(
-            "len() of unsized object"))
-
     def setitem(self, item, value):
         self.invalidated()
         self.dtype.setitem(self.storage, item, value)
 
-    def start_iter(self, res_shape=None):
-        if self.order == 'C':
-            if res_shape is not None and res_shape != self.shape:
-                return BroadcastIterator(self, res_shape)
-            return ArrayIterator(self.size)
-        raise NotImplementedError  # use ViewIterator simply, test it
-
     def setshape(self, space, new_shape):
         self.shape = new_shape
         self.calc_strides(new_shape)
 
-    def debug_repr(self):
-        return 'Array'
-
-    def get_storage(self, space):
-        return self.storage
+    def create_sig(self, res_shape):
+        return self.array_sig(res_shape)
 
     def __del__(self):
         lltype.free(self.storage, flavor='raw', track_allocation=False)
@@ -1396,10 +1105,11 @@
     )
     arr = W_NDimArray(size, shape[:], dtype=dtype, order=order)
     shapelen = len(shape)
-    arr_iter = arr.start_iter(arr.shape)
+    arr_iter = ArrayIterator(arr.size)
     for i in range(len(elems_w)):
         w_elem = elems_w[i]
-        dtype.setitem(arr.storage, arr_iter.offset, dtype.coerce(space, w_elem))
+        dtype.setitem(arr.storage, arr_iter.offset,
+                      dtype.coerce(space, w_elem))
         arr_iter = arr_iter.next(shapelen)
     return arr
 
@@ -1492,48 +1202,31 @@
 
 
 class W_FlatIterator(ViewArray):
-    signature = signature.BaseSignature()
 
     @jit.unroll_safe
     def __init__(self, arr):
+        arr = arr.get_concrete()
         size = 1
         for sh in arr.shape:
             size *= sh
-        new_sig = signature.Signature.find_sig([
-            W_FlatIterator.signature, arr.signature
-        ])
-        ViewArray.__init__(self, arr, new_sig, [arr.strides[-1]],
-                           [arr.backstrides[-1]], [size])
+        self.strides = [arr.strides[-1]]
+        self.backstrides = [arr.backstrides[-1]]
+        ViewArray.__init__(self, size, [size], arr.dtype, arr.order,
+                               arr)
         self.shapelen = len(arr.shape)
-        self.arr = arr
-        self.iter = self.start_iter()
-
-    def start_iter(self, res_shape=None):
-        if res_shape is not None and res_shape != self.shape:
-            return BroadcastIterator(self, res_shape)
-        return OneDimIterator(self.arr.start, self.strides[0],
-                              self.shape[0])
-
-    def find_dtype(self):
-        return self.arr.find_dtype()
-
-    def find_size(self):
-        return self.shape[0]
+        self.iter = OneDimIterator(arr.start, self.strides[0],
+                                   self.shape[0])
 
     def descr_next(self, space):
         if self.iter.done():
             raise OperationError(space.w_StopIteration, space.w_None)
-        result = self.eval(self.iter)
+        result = self.getitem(self.iter.offset)
         self.iter = self.iter.next(self.shapelen)
         return result
 
     def descr_iter(self):
         return self
 
-    def debug_repr(self):
-        return 'FlatIter(%s)' % self.arr.debug_repr()
-
-
 W_FlatIterator.typedef = TypeDef(
     'flatiter',
     next = interp2app(W_FlatIterator.descr_next),
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -2,20 +2,21 @@
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
-from pypy.module.micronumpy import interp_boxes, interp_dtype, signature, types
+from pypy.module.micronumpy import interp_boxes, interp_dtype, types
+from pypy.module.micronumpy.signature import ReduceSignature, ScalarSignature, find_sig
 from pypy.rlib import jit
 from pypy.rlib.rarithmetic import LONG_BIT
 from pypy.tool.sourcetools import func_with_new_name
 
-
 reduce_driver = jit.JitDriver(
-    greens = ['shapelen', "signature"],
-    reds = ["i", "self", "dtype", "value", "obj"]
+    greens = ['shapelen', "sig"],
+    virtualizables = ["frame"],
+    reds = ["frame", "self", "dtype", "value", "obj"]
 )
 
 class W_Ufunc(Wrappable):
     _attrs_ = ["name", "promote_to_float", "promote_bools", "identity"]
-    _immutable_fields_ = ["promote_to_float", "promote_bools"]
+    _immutable_fields_ = ["promote_to_float", "promote_bools", "name"]
 
     def __init__(self, name, promote_to_float, promote_bools, identity):
         self.name = name
@@ -50,6 +51,7 @@
 
     def reduce(self, space, w_obj, multidim):
         from pypy.module.micronumpy.interp_numarray import convert_to_array, Scalar
+        
         if self.argcount != 2:
             raise OperationError(space.w_ValueError, space.wrap("reduce only "
                 "supported for binary functions"))
@@ -60,13 +62,16 @@
             raise OperationError(space.w_TypeError, space.wrap("cannot reduce "
                 "on a scalar"))
 
-        size = obj.find_size()
+        size = obj.size
         dtype = find_unaryop_result_dtype(
             space, obj.find_dtype(),
             promote_to_largest=True
         )
-        start = obj.start_iter(obj.shape)
         shapelen = len(obj.shape)
+        sig = find_sig(ReduceSignature(self.func, self.name, dtype,
+                                       ScalarSignature(dtype),
+                                       obj.create_sig(obj.shape)), obj)
+        frame = sig.create_frame(obj)
         if shapelen > 1 and not multidim:
             raise OperationError(space.w_NotImplementedError,
                 space.wrap("not implemented yet"))
@@ -74,34 +79,33 @@
             if size == 0:
                 raise operationerrfmt(space.w_ValueError, "zero-size array to "
                     "%s.reduce without identity", self.name)
-            value = obj.eval(start).convert_to(dtype)
-            start = start.next(shapelen)
+            value = sig.eval(frame, obj).convert_to(dtype)
+            frame.next(shapelen)
         else:
             value = self.identity.convert_to(dtype)
-        new_sig = signature.Signature.find_sig([
-            self.reduce_signature, obj.signature
-        ])
-        return self.reduce_loop(new_sig, shapelen, start, value, obj, dtype)
+        return self.reduce_loop(shapelen, sig, frame, value, obj, dtype)
 
-    def reduce_loop(self, signature, shapelen, i, value, obj, dtype):
-        while not i.done():
-            reduce_driver.jit_merge_point(signature=signature,
+    def reduce_loop(self, shapelen, sig, frame, value, obj, dtype):
+        while not frame.done():
+            reduce_driver.jit_merge_point(sig=sig,
                                           shapelen=shapelen, self=self,
-                                          value=value, obj=obj, i=i,
+                                          value=value, obj=obj, frame=frame,
                                           dtype=dtype)
-            value = self.func(dtype, value, obj.eval(i).convert_to(dtype))
-            i = i.next(shapelen)
+            assert isinstance(sig, ReduceSignature)
+            value = sig.binfunc(dtype, value, sig.eval(frame, obj).convert_to(dtype))
+            frame.next(shapelen)
         return value
 
 class W_Ufunc1(W_Ufunc):
     argcount = 1
 
+    _immutable_fields_ = ["func", "name"]
+
     def __init__(self, func, name, promote_to_float=False, promote_bools=False,
         identity=None):
 
         W_Ufunc.__init__(self, name, promote_to_float, promote_bools, identity)
         self.func = func
-        self.signature = signature.Call1(func)
 
     def call(self, space, args_w):
         from pypy.module.micronumpy.interp_numarray import (Call1,
@@ -117,14 +121,13 @@
         if isinstance(w_obj, Scalar):
             return self.func(res_dtype, w_obj.value.convert_to(res_dtype))
 
-        new_sig = signature.Signature.find_sig([self.signature, w_obj.signature])
-        w_res = Call1(new_sig, w_obj.shape, res_dtype, w_obj, w_obj.order)
+        w_res = Call1(self.func, self.name, w_obj.shape, res_dtype, w_obj)
         w_obj.add_invalidates(w_res)
         return w_res
 
 
 class W_Ufunc2(W_Ufunc):
-    _immutable_fields_ = ["comparison_func", "func"]
+    _immutable_fields_ = ["comparison_func", "func", "name"]
     argcount = 2
 
     def __init__(self, func, name, promote_to_float=False, promote_bools=False,
@@ -133,8 +136,6 @@
         W_Ufunc.__init__(self, name, promote_to_float, promote_bools, identity)
         self.func = func
         self.comparison_func = comparison_func
-        self.signature = signature.Call2(func)
-        self.reduce_signature = signature.BaseSignature()
 
     def call(self, space, args_w):
         from pypy.module.micronumpy.interp_numarray import (Call2,
@@ -158,11 +159,9 @@
                 w_rhs.value.convert_to(calc_dtype)
             )
 
-        new_sig = signature.Signature.find_sig([
-            self.signature, w_lhs.signature, w_rhs.signature
-        ])
         new_shape = shape_agreement(space, w_lhs.shape, w_rhs.shape)
-        w_res = Call2(new_sig, new_shape, calc_dtype,
+        w_res = Call2(self.func, self.name,
+                      new_shape, calc_dtype,
                       res_dtype, w_lhs, w_rhs)
         w_lhs.add_invalidates(w_res)
         w_rhs.add_invalidates(w_res)
diff --git a/pypy/module/micronumpy/signature.py b/pypy/module/micronumpy/signature.py
--- a/pypy/module/micronumpy/signature.py
+++ b/pypy/module/micronumpy/signature.py
@@ -1,54 +1,322 @@
-from pypy.rlib.objectmodel import r_dict, compute_identity_hash
+from pypy.rlib.objectmodel import r_dict, compute_identity_hash, compute_hash
 from pypy.rlib.rarithmetic import intmask
+from pypy.module.micronumpy.interp_iter import ViewIterator, ArrayIterator, \
+     OneDimIterator, ConstantIterator
+from pypy.module.micronumpy.strides import calculate_slice_strides
+from pypy.rlib.jit import hint, unroll_safe, promote
 
+def sigeq(one, two):
+    return one.eq(two)
 
-def components_eq(lhs, rhs):
-    if len(lhs) != len(rhs):
-        return False
-    for i in range(len(lhs)):
-        v1, v2 = lhs[i], rhs[i]
-        if type(v1) is not type(v2) or not v1.eq(v2):
+def sigeq_no_numbering(one, two):
+    """ Cache for iterator numbering should not compare array numbers
+    """
+    return one.eq(two, compare_array_no=False)
+
+def sighash(sig):
+    return sig.hash()
+
+known_sigs = r_dict(sigeq, sighash)
+
+def find_sig(sig, arr):
+    sig.invent_array_numbering(arr)
+    try:
+        return known_sigs[sig]
+    except KeyError:
+        sig.invent_numbering()
+        known_sigs[sig] = sig
+        return sig
+
+class NumpyEvalFrame(object):
+    _virtualizable2_ = ['iterators[*]', 'final_iter', 'arraylist[*]']
+
+    @unroll_safe
+    def __init__(self, iterators, arrays):
+        self = hint(self, access_directly=True, fresh_virtualizable=True)
+        self.iterators = iterators[:]
+        self.arrays = arrays[:]
+        for i in range(len(self.iterators)):
+            iter = self.iterators[i]
+            if not isinstance(iter, ConstantIterator):
+                self.final_iter = i
+                break
+        else:
+            self.final_iter = -1
+
+    def done(self):
+        final_iter = promote(self.final_iter)
+        if final_iter < 0:
             return False
-    return True
+        return self.iterators[final_iter].done()
 
-def components_hash(components):
-    res = 0x345678
-    for component in components:
-        res = intmask((1000003 * res) ^ component.hash())
-    return res
+    @unroll_safe
+    def next(self, shapelen):
+        for i in range(len(self.iterators)):
+            self.iterators[i] = self.iterators[i].next(shapelen)
 
-class BaseSignature(object):
-    _attrs_ = []
+def _add_ptr_to_cache(ptr, cache):
+    i = 0
+    for p in cache:
+        if ptr == p:
+            return i
+        i += 1
+    else:
+        res = len(cache)
+        cache.append(ptr)
+        return res
 
-    def eq(self, other):
-        return self is other
+class Signature(object):
+    _attrs_ = ['iter_no', 'array_no']
+    _immutable_fields_ = ['iter_no', 'array_no']
+
+    array_no = 0
+    iter_no = 0
+
+    def invent_numbering(self):
+        cache = r_dict(sigeq_no_numbering, sighash)
+        allnumbers = []
+        self._invent_numbering(cache, allnumbers)
+
+    def invent_array_numbering(self, arr):
+        cache = []
+        self._invent_array_numbering(arr, cache)
+
+    def _invent_numbering(self, cache, allnumbers):
+        try:
+            no = cache[self]
+        except KeyError:
+            no = len(allnumbers)
+            cache[self] = no
+            allnumbers.append(no)
+        self.iter_no = no
+
+    def create_frame(self, arr, res_shape=None):
+        res_shape = res_shape or arr.shape
+        iterlist = []
+        arraylist = []
+        self._create_iter(iterlist, arraylist, arr, res_shape, [])
+        return NumpyEvalFrame(iterlist, arraylist)
+
+class ConcreteSignature(Signature):
+    _immutable_fields_ = ['dtype']
+
+    def __init__(self, dtype):
+        self.dtype = dtype
+
+    def eq(self, other, compare_array_no=True):
+        if type(self) is not type(other):
+            return False
+        assert isinstance(other, ConcreteSignature)
+        if compare_array_no:
+            if self.array_no != other.array_no:
+                return False
+        return self.dtype is other.dtype
 
     def hash(self):
-        return compute_identity_hash(self)
+        return compute_identity_hash(self.dtype)
 
-class Signature(BaseSignature):
-    _known_sigs = r_dict(components_eq, components_hash)
+    def allocate_view_iter(self, arr, res_shape, chunklist):
+        r = arr.shape, arr.start, arr.strides, arr.backstrides
+        if chunklist:
+            for chunkelem in chunklist:
+                r = calculate_slice_strides(r[0], r[1], r[2], r[3], chunkelem)
+        shape, start, strides, backstrides = r
+        if len(res_shape) == 1:
+            return OneDimIterator(start, strides[0], res_shape[0])
+        return ViewIterator(start, strides, backstrides, shape, res_shape)
 
-    _attrs_ = ["components"]
-    _immutable_fields_ = ["components[*]"]
+class ArraySignature(ConcreteSignature):
+    def debug_repr(self):
+        return 'Array'
 
-    def __init__(self, components):
-        self.components = components
+    def _invent_array_numbering(self, arr, cache):
+        from pypy.module.micronumpy.interp_numarray import ConcreteArray
+        concr = arr.get_concrete()
+        assert isinstance(concr, ConcreteArray)
+        self.array_no = _add_ptr_to_cache(concr.storage, cache)
 
-    @staticmethod
-    def find_sig(components):
-        return Signature._known_sigs.setdefault(components, Signature(components))
+    def _create_iter(self, iterlist, arraylist, arr, res_shape, chunklist):
+        from pypy.module.micronumpy.interp_numarray import ConcreteArray
+        concr = arr.get_concrete()
+        assert isinstance(concr, ConcreteArray)
+        storage = concr.storage
+        if self.iter_no >= len(iterlist):
+            iterlist.append(self.allocate_iter(concr, res_shape, chunklist))
+        if self.array_no >= len(arraylist):
+            arraylist.append(storage)
 
-class Call1(BaseSignature):
-    _immutable_fields_ = ["func", "name"]
+    def allocate_iter(self, arr, res_shape, chunklist):
+        if chunklist:
+            return self.allocate_view_iter(arr, res_shape, chunklist)
+        return ArrayIterator(arr.size)
 
-    def __init__(self, func):
-        self.func = func
-        self.name = func.func_name
+    def eval(self, frame, arr):
+        iter = frame.iterators[self.iter_no]
+        return self.dtype.getitem(frame.arrays[self.array_no], iter.offset)
 
-class Call2(BaseSignature):
-    _immutable_fields_ = ["func", "name"]
+class ScalarSignature(ConcreteSignature):
+    def debug_repr(self):
+        return 'Scalar'
 
-    def __init__(self, func):
-        self.func = func
-        self.name = func.func_name
+    def _invent_array_numbering(self, arr, cache):
+        pass
+
+    def _create_iter(self, iterlist, arraylist, arr, res_shape, chunklist):
+        if self.iter_no >= len(iterlist):
+            iter = ConstantIterator()
+            iterlist.append(iter)
+
+    def eval(self, frame, arr):
+        from pypy.module.micronumpy.interp_numarray import Scalar
+        assert isinstance(arr, Scalar)
+        return arr.value
+
+class ViewSignature(ArraySignature):
+    def debug_repr(self):
+        return 'Slice'
+
+    def _invent_numbering(self, cache, allnumbers):
+        # always invent a new number for view
+        no = len(allnumbers)
+        allnumbers.append(no)
+        self.iter_no = no
+
+    def allocate_iter(self, arr, res_shape, chunklist):
+        return self.allocate_view_iter(arr, res_shape, chunklist)
+
+class VirtualSliceSignature(Signature):
+    def __init__(self, child):
+        self.child = child
+
+    def _invent_array_numbering(self, arr, cache):
+        from pypy.module.micronumpy.interp_numarray import VirtualSlice
+        assert isinstance(arr, VirtualSlice)
+        self.child._invent_array_numbering(arr.child, cache)
+
+    def hash(self):
+        return intmask(self.child.hash() ^ 1234)
+
+    def eq(self, other, compare_array_no=True):
+        if type(self) is not type(other):
+            return False
+        assert isinstance(other, VirtualSliceSignature)
+        return self.child.eq(other.child, compare_array_no)
+
+    def _create_iter(self, iterlist, arraylist, arr, res_shape, chunklist):
+        from pypy.module.micronumpy.interp_numarray import VirtualSlice
+        assert isinstance(arr, VirtualSlice)
+        chunklist.append(arr.chunks)
+        self.child._create_iter(iterlist, arraylist, arr.child, res_shape,
+                                chunklist)
+
+    def eval(self, frame, arr):
+        from pypy.module.micronumpy.interp_numarray import VirtualSlice
+        assert isinstance(arr, VirtualSlice)
+        return self.child.eval(frame, arr.child)
+
+class Call1(Signature):
+    _immutable_fields_ = ['unfunc', 'name', 'child']
+
+    def __init__(self, func, name, child):
+        self.unfunc = func
+        self.child = child
+        self.name = name
+
+    def hash(self):
+        return compute_hash(self.name) ^ intmask(self.child.hash() << 1)
+
+    def eq(self, other, compare_array_no=True):
+        if type(self) is not type(other):
+            return False
+        assert isinstance(other, Call1)
+        return (self.unfunc is other.unfunc and
+                self.child.eq(other.child, compare_array_no))
+
+    def debug_repr(self):
+        return 'Call1(%s, %s)' % (self.name, self.child.debug_repr())
+
+    def _invent_numbering(self, cache, allnumbers):
+        self.child._invent_numbering(cache, allnumbers)
+
+    def _invent_array_numbering(self, arr, cache):
+        from pypy.module.micronumpy.interp_numarray import Call1
+        assert isinstance(arr, Call1)
+        self.child._invent_array_numbering(arr.values, cache)
+
+    def _create_iter(self, iterlist, arraylist, arr, res_shape, chunklist):
+        from pypy.module.micronumpy.interp_numarray import Call1
+        assert isinstance(arr, Call1)
+        self.child._create_iter(iterlist, arraylist, arr.values, res_shape,
+                                chunklist)
+
+    def eval(self, frame, arr):
+        from pypy.module.micronumpy.interp_numarray import Call1
+        assert isinstance(arr, Call1)
+        v = self.child.eval(frame, arr.values).convert_to(arr.res_dtype)
+        return self.unfunc(arr.res_dtype, v)
+
+class Call2(Signature):
+    _immutable_fields_ = ['binfunc', 'name', 'calc_dtype', 'left', 'right']
+
+    def __init__(self, func, name, calc_dtype, left, right):
+        self.binfunc = func
+        self.left = left
+        self.right = right
+        self.name = name
+        self.calc_dtype = calc_dtype
+
+    def hash(self):
+        return (compute_hash(self.name) ^ intmask(self.left.hash() << 1) ^
+                intmask(self.right.hash() << 2))
+
+    def eq(self, other, compare_array_no=True):
+        if type(self) is not type(other):
+            return False
+        assert isinstance(other, Call2)
+        return (self.binfunc is other.binfunc and
+                self.calc_dtype is other.calc_dtype and
+                self.left.eq(other.left, compare_array_no) and
+                self.right.eq(other.right, compare_array_no))
+
+    def _invent_array_numbering(self, arr, cache):
+        from pypy.module.micronumpy.interp_numarray import Call2
+        assert isinstance(arr, Call2)
+        self.left._invent_array_numbering(arr.left, cache)
+        self.right._invent_array_numbering(arr.right, cache)
+
+    def _invent_numbering(self, cache, allnumbers):
+        self.left._invent_numbering(cache, allnumbers)
+        self.right._invent_numbering(cache, allnumbers)
+
+    def _create_iter(self, iterlist, arraylist, arr, res_shape, chunklist):
+        from pypy.module.micronumpy.interp_numarray import Call2
+
+        assert isinstance(arr, Call2)
+        self.left._create_iter(iterlist, arraylist, arr.left, res_shape,
+                               chunklist)
+        self.right._create_iter(iterlist, arraylist, arr.right, res_shape,
+                                chunklist)
+
+    def eval(self, frame, arr):
+        from pypy.module.micronumpy.interp_numarray import Call2
+        assert isinstance(arr, Call2)
+        lhs = self.left.eval(frame, arr.left).convert_to(self.calc_dtype)
+        rhs = self.right.eval(frame, arr.right).convert_to(self.calc_dtype)
+        return self.binfunc(self.calc_dtype, lhs, rhs)
+
+    def debug_repr(self):
+        return 'Call2(%s, %s, %s)' % (self.name, self.left.debug_repr(),
+                                      self.right.debug_repr())
+
+class ReduceSignature(Call2):
+    def _create_iter(self, iterlist, arraylist, arr, res_shape, chunklist):
+        self.right._create_iter(iterlist, arraylist, arr, res_shape, chunklist)
+
+    def _invent_numbering(self, cache, allnumbers):
+        self.right._invent_numbering(cache, allnumbers)
+
+    def _invent_array_numbering(self, arr, cache):
+        self.right._invent_array_numbering(arr, cache)
+
+    def eval(self, frame, arr):
+        return self.right.eval(frame, arr)
diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/strides.py
@@ -0,0 +1,34 @@
+
+def calculate_slice_strides(shape, start, strides, backstrides, chunks):
+    rstrides = []
+    rbackstrides = []
+    rstart = start
+    rshape = []
+    i = -1
+    for i, (start_, stop, step, lgt) in enumerate(chunks):
+        if step != 0:
+            rstrides.append(strides[i] * step)
+            rbackstrides.append(strides[i] * (lgt - 1) * step)
+            rshape.append(lgt)
+        rstart += strides[i] * start_
+    # add a reminder
+    s = i + 1
+    assert s >= 0
+    rstrides += strides[s:]
+    rbackstrides += backstrides[s:]
+    rshape += shape[s:]
+    return rshape, rstart, rstrides, rbackstrides
+
+def calculate_broadcast_strides(strides, backstrides, orig_shape, res_shape):
+    rstrides = []
+    rbackstrides = []
+    for i in range(len(orig_shape)):
+        if orig_shape[i] == 1:
+            rstrides.append(0)
+            rbackstrides.append(0)
+        else:
+            rstrides.append(strides[i])
+            rbackstrides.append(backstrides[i])
+    rstrides = [0] * (len(res_shape) - len(orig_shape)) + rstrides
+    rbackstrides = [0] * (len(res_shape) - len(orig_shape)) + rbackstrides
+    return rstrides, rbackstrides
diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py
--- a/pypy/module/micronumpy/test/test_base.py
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -4,7 +4,6 @@
 from pypy.module.micronumpy.interp_ufuncs import (find_binop_result_dtype,
         find_unaryop_result_dtype)
 
-
 class BaseNumpyAppTest(object):
     def setup_class(cls):
         cls.space = gettestobjspace(usemodules=['micronumpy'])
@@ -15,20 +14,37 @@
         bool_dtype = get_dtype_cache(space).w_booldtype
 
         ar = W_NDimArray(10, [10], dtype=float64_dtype)
+        ar2 = W_NDimArray(10, [10], dtype=float64_dtype)
         v1 = ar.descr_add(space, ar)
         v2 = ar.descr_add(space, Scalar(float64_dtype, 2.0))
-        assert v1.signature is not v2.signature
+        sig1 = v1.find_sig()
+        sig2 = v2.find_sig()
+        assert v1 is not v2
+        assert sig1.left.iter_no == sig1.right.iter_no
+        assert sig2.left.iter_no != sig2.right.iter_no
+        assert sig1.left.array_no == sig1.right.array_no
+        sig1b = ar2.descr_add(space, ar).find_sig()
+        assert sig1b.left.array_no != sig1b.right.array_no
+        assert sig1b is not sig1
         v3 = ar.descr_add(space, Scalar(float64_dtype, 1.0))
-        assert v2.signature is v3.signature
+        sig3 = v3.find_sig()
+        assert sig2 is sig3
         v4 = ar.descr_add(space, ar)
-        assert v1.signature is v4.signature
+        assert v1.find_sig() is v4.find_sig()
 
         bool_ar = W_NDimArray(10, [10], dtype=bool_dtype)
         v5 = ar.descr_add(space, bool_ar)
-        assert v5.signature is not v1.signature
-        assert v5.signature is not v2.signature
+        assert v5.find_sig() is not v1.find_sig()
+        assert v5.find_sig() is not v2.find_sig()
         v6 = ar.descr_add(space, bool_ar)
-        assert v5.signature is v6.signature
+        assert v5.find_sig() is v6.find_sig()
+        v7 = v6.descr_add(space, v6)
+        sig7 = v7.find_sig()
+        assert sig7.left.left.iter_no == sig7.right.left.iter_no
+        assert sig7.left.left.iter_no != sig7.right.right.iter_no
+        assert sig7.left.right.iter_no == sig7.right.right.iter_no
+        v1.forced_result = ar
+        assert v1.find_sig() is not sig1
 
     def test_slice_signature(self, space):
         float64_dtype = get_dtype_cache(space).w_float64dtype
@@ -36,11 +52,14 @@
         ar = W_NDimArray(10, [10], dtype=float64_dtype)
         v1 = ar.descr_getitem(space, space.wrap(slice(1, 3, 1)))
         v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1)))
-        assert v1.signature is v2.signature
+        assert v1.find_sig() is v2.find_sig()
 
         v3 = v2.descr_add(space, v1)
         v4 = v1.descr_add(space, v2)
-        assert v3.signature is v4.signature
+        assert v3.find_sig() is v4.find_sig()
+        v5 = ar.descr_add(space, ar).descr_getitem(space, space.wrap(slice(1, 3, 1)))
+        v6 = ar.descr_add(space, ar).descr_getitem(space, space.wrap(slice(1, 4, 1)))
+        assert v5.find_sig() is v6.find_sig()
 
 class TestUfuncCoerscion(object):
     def test_binops(self, space):
diff --git a/pypy/module/micronumpy/test/test_compile.py b/pypy/module/micronumpy/test/test_compile.py
--- a/pypy/module/micronumpy/test/test_compile.py
+++ b/pypy/module/micronumpy/test/test_compile.py
@@ -137,6 +137,16 @@
         interp = self.run(code)
         assert interp.results[0].value.value == 15
 
+    def test_sum2(self):
+        code = """
+        a = |30|
+        b = a + a
+        sum(b)
+        """
+        interp = self.run(code)
+        assert interp.results[0].value.value == 30 * (30 - 1)
+
+
     def test_array_write(self):
         code = """
         a = [1,2,3,4,5]
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -8,8 +8,6 @@
 
 
 class MockDtype(object):
-    signature = signature.BaseSignature()
-
     def malloc(self, size):
         return None
 
@@ -38,92 +36,86 @@
         assert a.backstrides == [135, 12, 2]
 
     def test_create_slice_f(self):
-        space = self.space
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
-        s = a.create_slice(space, [(3, 0, 0, 1)])
+        s = a.create_slice([(3, 0, 0, 1)])
         assert s.start == 3
         assert s.strides == [10, 50]
         assert s.backstrides == [40, 100]
-        s = a.create_slice(space, [(1, 9, 2, 4)])
+        s = a.create_slice([(1, 9, 2, 4)])
         assert s.start == 1
         assert s.strides == [2, 10, 50]
         assert s.backstrides == [6, 40, 100]
-        s = a.create_slice(space, [(1, 5, 3, 2), (1, 2, 1, 1), (1, 0, 0, 1)])
+        s = a.create_slice([(1, 5, 3, 2), (1, 2, 1, 1), (1, 0, 0, 1)])
         assert s.shape == [2, 1]
         assert s.strides == [3, 10]
         assert s.backstrides == [3, 0]
-        s = a.create_slice(space, [(0, 10, 1, 10), (2, 0, 0, 1)])
+        s = a.create_slice([(0, 10, 1, 10), (2, 0, 0, 1)])
         assert s.start == 20
         assert s.shape == [10, 3]
 
     def test_create_slice_c(self):
-        space = self.space
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'C')
-        s = a.create_slice(space, [(3, 0, 0, 1)])
+        s = a.create_slice([(3, 0, 0, 1)])
         assert s.start == 45
         assert s.strides == [3, 1]
         assert s.backstrides == [12, 2]
-        s = a.create_slice(space, [(1, 9, 2, 4)])
+        s = a.create_slice([(1, 9, 2, 4)])
         assert s.start == 15
         assert s.strides == [30, 3, 1]
         assert s.backstrides == [90, 12, 2]
-        s = a.create_slice(space, [(1, 5, 3, 2), (1, 2, 1, 1), (1, 0, 0, 1)])
+        s = a.create_slice([(1, 5, 3, 2), (1, 2, 1, 1), (1, 0, 0, 1)])
         assert s.start == 19
         assert s.shape == [2, 1]
         assert s.strides == [45, 3]
         assert s.backstrides == [45, 0]
-        s = a.create_slice(space, [(0, 10, 1, 10), (2, 0, 0, 1)])
+        s = a.create_slice([(0, 10, 1, 10), (2, 0, 0, 1)])
         assert s.start == 6
         assert s.shape == [10, 3]
 
     def test_slice_of_slice_f(self):
-        space = self.space
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
-        s = a.create_slice(space, [(5, 0, 0, 1)])
+        s = a.create_slice([(5, 0, 0, 1)])
         assert s.start == 5
-        s2 = s.create_slice(space, [(3, 0, 0, 1)])
+        s2 = s.create_slice([(3, 0, 0, 1)])
         assert s2.shape == [3]
         assert s2.strides == [50]
         assert s2.parent is a
         assert s2.backstrides == [100]
         assert s2.start == 35
-        s = a.create_slice(space, [(1, 5, 3, 2)])
-        s2 = s.create_slice(space, [(0, 2, 1, 2), (2, 0, 0, 1)])
+        s = a.create_slice([(1, 5, 3, 2)])
+        s2 = s.create_slice([(0, 2, 1, 2), (2, 0, 0, 1)])
         assert s2.shape == [2, 3]
         assert s2.strides == [3, 50]
         assert s2.backstrides == [3, 100]
         assert s2.start == 1 * 15 + 2 * 3
 
     def test_slice_of_slice_c(self):
-        space = self.space
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), order='C')
-        s = a.create_slice(space, [(5, 0, 0, 1)])
+        s = a.create_slice([(5, 0, 0, 1)])
         assert s.start == 15 * 5
-        s2 = s.create_slice(space, [(3, 0, 0, 1)])
+        s2 = s.create_slice([(3, 0, 0, 1)])
         assert s2.shape == [3]
         assert s2.strides == [1]
         assert s2.parent is a
         assert s2.backstrides == [2]
         assert s2.start == 5 * 15 + 3 * 3
-        s = a.create_slice(space, [(1, 5, 3, 2)])
-        s2 = s.create_slice(space, [(0, 2, 1, 2), (2, 0, 0, 1)])
+        s = a.create_slice([(1, 5, 3, 2)])
+        s2 = s.create_slice([(0, 2, 1, 2), (2, 0, 0, 1)])
         assert s2.shape == [2, 3]
         assert s2.strides == [45, 1]
         assert s2.backstrides == [45, 2]
         assert s2.start == 1 * 15 + 2 * 3
 
     def test_negative_step_f(self):
-        space = self.space
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
-        s = a.create_slice(space, [(9, -1, -2, 5)])
+        s = a.create_slice([(9, -1, -2, 5)])
         assert s.start == 9
         assert s.strides == [-2, 10, 50]
         assert s.backstrides == [-8, 40, 100]
 
     def test_negative_step_c(self):
-        space = self.space
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), order='C')
-        s = a.create_slice(space, [(9, -1, -2, 5)])
+        s = a.create_slice([(9, -1, -2, 5)])
         assert s.start == 135
         assert s.strides == [-30, 3, 1]
         assert s.backstrides == [-120, 12, 2]
@@ -132,7 +124,7 @@
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
         r = a._index_of_single_item(self.space, self.newtuple(1, 2, 2))
         assert r == 1 + 2 * 10 + 2 * 50
-        s = a.create_slice(self.space, [(0, 10, 1, 10), (2, 0, 0, 1)])
+        s = a.create_slice([(0, 10, 1, 10), (2, 0, 0, 1)])
         r = s._index_of_single_item(self.space, self.newtuple(1, 0))
         assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 0))
         r = s._index_of_single_item(self.space, self.newtuple(1, 1))
@@ -142,7 +134,7 @@
         a = W_NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'C')
         r = a._index_of_single_item(self.space, self.newtuple(1, 2, 2))
         assert r == 1 * 3 * 5 + 2 * 3 + 2
-        s = a.create_slice(self.space, [(0, 10, 1, 10), (2, 0, 0, 1)])
+        s = a.create_slice([(0, 10, 1, 10), (2, 0, 0, 1)])
         r = s._index_of_single_item(self.space, self.newtuple(1, 0))
         assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 0))
         r = s._index_of_single_item(self.space, self.newtuple(1, 1))
@@ -897,13 +889,32 @@
         a = zeros(1)
         assert debug_repr(a) == 'Array'
         assert debug_repr(a + a) == 'Call2(add, Array, Array)'
-        assert debug_repr(a[::2]) == 'Slice(Array)'
+        assert debug_repr(a[::2]) == 'Slice'
         assert debug_repr(a + 2) == 'Call2(add, Array, Scalar)'
-        assert debug_repr(a + a.flat) == 'Call2(add, Array, FlatIter(Array))'
+        assert debug_repr(a + a.flat) == 'Call2(add, Array, Slice)'
         assert debug_repr(sin(a)) == 'Call1(sin, Array)'
+
         b = a + a
         b[0] = 3
-        assert debug_repr(b) == 'Call2(add, forced=Array)'
+        assert debug_repr(b) == 'Array'
+
+    def test_virtual_views(self):
+        from numpypy import arange
+        a = arange(15)
+        c = (a + a)
+        d = c[::2]
+        assert d[3] == 12
+        c[6] = 5
+        assert d[3] == 5
+        a = arange(15)
+        c = (a + a)
+        d = c[::2][::2]
+        assert d[1] == 8
+        b = a + a
+        c = b[::2]
+        c[:] = 3
+        assert b[0] == 3
+        assert b[1] == 2
 
     def test_tolist_scalar(self):
         from numpypy import int32, bool_
@@ -1066,6 +1077,17 @@
         a = ones((1, 2, 3))
         assert a[0, 1, 2] == 1.0
 
+    def test_multidim_setslice(self):
+        from numpypy import zeros, ones
+        a = zeros((3, 3))
+        b = ones((3, 3))
+        a[:,1:3] = b[:,1:3]
+        assert (a == [[0, 1, 1], [0, 1, 1], [0, 1, 1]]).all()
+        a = zeros((3, 3))
+        b = ones((3, 3))
+        a[:,::2] = b[:,::2]
+        assert (a == [[1, 0, 1], [1, 0, 1], [1, 0, 1]]).all()
+
     def test_broadcast_ufunc(self):
         from numpypy import array
         a = array([[1, 2], [3, 4], [5, 6]])
@@ -1075,10 +1097,10 @@
 
     def test_broadcast_setslice(self):
         from numpypy import zeros, ones
-        a = zeros((100, 100))
-        b = ones(100)
+        a = zeros((10, 10))
+        b = ones(10)
         a[:, :] = b
-        assert a[13, 15] == 1
+        assert a[3, 5] == 1
 
     def test_broadcast_shape_agreement(self):
         from numpypy import zeros, array
@@ -1112,6 +1134,14 @@
         b[:] = (a + a)
         assert (b == zeros((4, 3, 5))).all()
 
+    def test_broadcast_virtualview(self):
+        from numpypy import arange, zeros
+        a = arange(8).reshape([2, 2, 2])
+        b = (a + a)[1, 1]
+        c = zeros((2, 2, 2))
+        c[:] = b
+        assert (c == [[[12, 14], [12, 14]], [[12, 14], [12, 14]]]).all()
+
     def test_argmax(self):
         from numpypy import array
         a = array([[1, 2], [3, 4], [5, 6]])
@@ -1173,6 +1203,11 @@
         a = array([1, 2, 3])
         assert dot(a.flat, a.flat) == 14
 
+    def test_flatiter_varray(self):
+        from numpypy import ones
+        a = ones((2, 2))
+        assert list(((a + a).flat)) == [2, 2, 2, 2]
+
     def test_slice_copy(self):
         from numpypy import zeros
         a = zeros((10, 10))
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -49,10 +49,14 @@
             interp.run(space)
             w_res = interp.results[-1]
             if isinstance(w_res, BaseArray):
-                w_res = w_res.eval(w_res.start_iter())
-
+                concr = w_res.get_concrete_or_scalar()
+                sig = concr.find_sig()
+                frame = sig.create_frame(concr)
+                w_res = sig.eval(frame, concr)
             if isinstance(w_res, interp_boxes.W_Float64Box):
                 return w_res.value
+            if isinstance(w_res, interp_boxes.W_Int64Box):
+                return float(w_res.value)
             elif isinstance(w_res, interp_boxes.W_BoolBox):
                 return float(w_res.value)
             raise TypeError(w_res)
@@ -78,8 +82,9 @@
     def test_add(self):
         result = self.run("add")
         self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add': 1,
-                                'setinteriorfield_raw': 1, 'int_add': 3,
-                                'int_ge': 1, 'guard_false': 1, 'jump': 1})
+                                'setinteriorfield_raw': 1, 'int_add': 2,
+                                'int_ge': 1, 'guard_false': 1, 'jump': 1,
+                                'arraylen_gc': 1})
         assert result == 3 + 3
 
     def define_float_add():
@@ -93,7 +98,8 @@
         assert result == 3 + 3
         self.check_simple_loop({"getinteriorfield_raw": 1, "float_add": 1,
                                 "setinteriorfield_raw": 1, "int_add": 2,
-                                "int_ge": 1, "guard_false": 1, "jump": 1})
+                                "int_ge": 1, "guard_false": 1, "jump": 1,
+                                'arraylen_gc': 1})
 
     def define_sum():
         return """
@@ -106,8 +112,8 @@
         result = self.run("sum")
         assert result == 2 * sum(range(30))
         self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 2,
-                                "int_add": 2, "int_ge": 1, "guard_false": 1,
-                                "jump": 1})
+                                "int_add": 1, "int_ge": 1, "guard_false": 1,
+                                "jump": 1, 'arraylen_gc': 1})
 
     def define_prod():
         return """
@@ -123,18 +129,22 @@
             expected *= i * 2
         assert result == expected
         self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
-                                "float_mul": 1, "int_add": 2,
-                                "int_ge": 1, "guard_false": 1, "jump": 1})
+                                "float_mul": 1, "int_add": 1,
+                                "int_ge": 1, "guard_false": 1, "jump": 1,
+                                'arraylen_gc': 1})
 
-    def test_max(self):
-        py.test.skip("broken, investigate")
-        result = self.run("""
+    def define_max():
+        return """
         a = |30|
         a[13] = 128
         b = a + a
         max(b)
-        """)
+        """
+
+    def test_max(self):
+        result = self.run("max")
         assert result == 256
+        py.test.skip("not there yet, getting though")
         self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
                                 "float_mul": 1, "int_add": 1,
                                 "int_lt": 1, "guard_true": 1, "jump": 1})
@@ -164,9 +174,9 @@
         result = self.run("any")
         assert result == 1
         self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
-                                "float_ne": 1, "int_add": 2,
+                                "float_ne": 1, "int_add": 1,
                                 "int_ge": 1, "jump": 1,
-                                "guard_false": 2})
+                                "guard_false": 2, 'arraylen_gc': 1})
 
     def define_already_forced():
         return """
@@ -183,14 +193,13 @@
         # This is the sum of the ops for both loops, however if you remove the
         # optimization then you end up with 2 float_adds, so we can still be
         # sure it was optimized correctly.
-        # XXX the comment above is wrong now.  We need preferrably a way to
-        # count the two loops separately
-        self.check_resops({'setinteriorfield_raw': 4, 'guard_nonnull': 1,
-                           'getfield_gc': 35, 'getfield_gc_pure': 6,
-                           'guard_class': 22, 'int_add': 8, 'float_mul': 2,
-                           'guard_isnull': 2, 'jump': 2, 'int_ge': 4,
-                           'getinteriorfield_raw': 4, 'float_add': 2, 'guard_false': 4,
-                           'guard_value': 2})
+        self.check_resops({'setinteriorfield_raw': 4, 'getfield_gc': 26,
+                           'getarrayitem_gc': 4, 'getarrayitem_gc_pure': 2,
+                           'getfield_gc_pure': 4,
+                           'guard_class': 8, 'int_add': 8, 'float_mul': 2,
+                           'jump': 2, 'int_ge': 4,
+                           'getinteriorfield_raw': 4, 'float_add': 2,
+                           'guard_false': 4, 'arraylen_gc': 2, 'same_as': 2})
 
     def define_ufunc():
         return """
@@ -204,8 +213,9 @@
         result = self.run("ufunc")
         assert result == -6
         self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1, "float_neg": 1,
-                                "setinteriorfield_raw": 1, "int_add": 3,
-                                "int_ge": 1, "guard_false": 1, "jump": 1})
+                                "setinteriorfield_raw": 1, "int_add": 2,
+                                "int_ge": 1, "guard_false": 1, "jump": 1,
+                                'arraylen_gc': 1})
 
     def define_specialization():
         return """
@@ -248,7 +258,8 @@
                                 'setinteriorfield_raw': 1,
                                 'int_add': 3,
                                 'int_ge': 1, 'guard_false': 1,
-                                'jump': 1})
+                                'jump': 1,
+                                'arraylen_gc': 1})
 
     def define_multidim():
         return """
@@ -263,8 +274,9 @@
         # int_add might be 1 here if we try slightly harder with
         # reusing indexes or some optimization
         self.check_simple_loop({'float_add': 1, 'getinteriorfield_raw': 2,
-                                'guard_false': 1, 'int_add': 3, 'int_ge': 1,
-                                'jump': 1, 'setinteriorfield_raw': 1})
+                                'guard_false': 1, 'int_add': 2, 'int_ge': 1,
+                                'jump': 1, 'setinteriorfield_raw': 1,
+                                'arraylen_gc': 1})
 
     def define_multidim_slice():
         return """
@@ -312,7 +324,25 @@
         self.check_trace_count(1)
         self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add' : 1,
                                 'setinteriorfield_raw': 1, 'int_add': 3,
-                                'int_eq': 1, 'guard_false': 1, 'jump': 1})
+                                'int_lt': 1, 'guard_true': 1, 'jump': 1,
+                                'arraylen_gc': 3})
+
+    def define_virtual_slice():
+        return """
+        a = |30|
+        c = a + a
+        d = c -> 1:20
+        d -> 1
+        """
+
+    def test_virtual_slice(self):
+        result = self.run("virtual_slice")
+        assert result == 4
+        self.check_trace_count(1)
+        self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add' : 1,
+                                'setinteriorfield_raw': 1, 'int_add': 2,
+                                'int_ge': 1, 'guard_false': 1, 'jump': 1,
+                                'arraylen_gc': 1})
 
 class TestNumpyOld(LLJitMixin):
     def setup_class(cls):
diff --git a/pypy/module/micronumpy/test/test_ztranslation.py b/pypy/module/micronumpy/test/test_ztranslation.py
--- a/pypy/module/micronumpy/test/test_ztranslation.py
+++ b/pypy/module/micronumpy/test/test_ztranslation.py
@@ -1,5 +1,8 @@
-
+from pypy.module.micronumpy import signature
 from pypy.objspace.fake.checkmodule import checkmodule
 
 def test_numpy_translates():
+    # XXX: If there are signatures floating around this might explode. This fix
+    # is ugly.
+    signature.known_sigs.clear()
     checkmodule('micronumpy')
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -252,7 +252,7 @@
         # grow the list
         done = 0
         while done < len(self._seen_extras):
-            print self._seen_extras
+            #print self._seen_extras
             ann.build_types(self._seen_extras[done], [],
                             complete_now=False)
             done += 1
diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py
--- a/pypy/objspace/flow/flowcontext.py
+++ b/pypy/objspace/flow/flowcontext.py
@@ -185,7 +185,7 @@
 class FlowExecutionContext(ExecutionContext):
 
     def __init__(self, space, code, globals, constargs={}, outer_func=None,
-                 name=None):
+                 name=None, is_generator=False):
         ExecutionContext.__init__(self, space)
         self.code = code
 
@@ -208,6 +208,7 @@
         initialblock = SpamBlock(FrameState(frame).copy())
         self.pendingblocks = collections.deque([initialblock])
         self.graph = FunctionGraph(name or code.co_name, initialblock)
+        self.is_generator = is_generator
 
     make_link = Link # overridable for transition tracking
 
@@ -247,6 +248,8 @@
         return outcome, w_exc_cls, w_exc_value
 
     def build_flow(self):
+        if self.is_generator:
+            self.produce_generator_mark()
         while self.pendingblocks:
             block = self.pendingblocks.popleft()
             frame = self.create_frame()
@@ -259,9 +262,15 @@
                 self.topframeref = jit.non_virtual_ref(frame)
                 self.crnt_frame = frame
                 try:
-                    w_result = frame.dispatch(frame.pycode,
-                                              frame.last_instr,
-                                              self)
+                    frame.frame_finished_execution = False
+                    while True:
+                        w_result = frame.dispatch(frame.pycode,
+                                                  frame.last_instr,
+                                                  self)
+                        if frame.frame_finished_execution:
+                            break
+                        else:
+                            self.generate_yield(frame, w_result)
                 finally:
                     self.crnt_frame = None
                     self.topframeref = old_frameref
@@ -307,6 +316,21 @@
             del self.recorder
         self.fixeggblocks()
 
+    def produce_generator_mark(self):
+        [initialblock] = self.pendingblocks
+        initialblock.operations.append(
+            SpaceOperation('generator_mark', [], Variable()))
+
+    def generate_yield(self, frame, w_result):
+        assert self.is_generator
+        self.recorder.crnt_block.operations.append(
+            SpaceOperation('yield', [w_result], Variable()))
+        # we must push a dummy value that will be POPped: it's the .send()
+        # passed into the generator (2.5 feature)
+        assert sys.version_info >= (2, 5)
+        frame.pushvalue(None)
+        frame.last_instr += 1
+
     def fixeggblocks(self):
         # EggBlocks reuse the variables of their previous block,
         # which is deemed not acceptable for simplicity of the operations
diff --git a/pypy/objspace/flow/objspace.py b/pypy/objspace/flow/objspace.py
--- a/pypy/objspace/flow/objspace.py
+++ b/pypy/objspace/flow/objspace.py
@@ -8,6 +8,7 @@
 from pypy.interpreter.pycode import PyCode, cpython_code_signature
 from pypy.interpreter.module import Module
 from pypy.interpreter.error import OperationError
+from pypy.interpreter.astcompiler.consts import CO_GENERATOR
 from pypy.interpreter import pyframe, argument
 from pypy.objspace.flow.model import *
 from pypy.objspace.flow import flowcontext, operation, specialcase
@@ -247,15 +248,13 @@
                 return ecls
         return None
 
-    def build_flow(self, func, constargs={}):
+    def build_flow(self, func, constargs={}, tweak_for_generator=True):
         """
         """
         if func.func_doc and func.func_doc.lstrip().startswith('NOT_RPYTHON'):
             raise Exception, "%r is tagged as NOT_RPYTHON" % (func,)
         code = func.func_code
-        if code.co_flags & 32:
-            # generator
-            raise TypeError("%r is a generator" % (func,))
+        is_generator = bool(code.co_flags & CO_GENERATOR)
         code = PyCode._from_code(self, code)
         if func.func_closure is None:
             cl = None
@@ -271,7 +270,8 @@
         class outerfunc: # hack
             closure = cl
         ec = flowcontext.FlowExecutionContext(self, code, func.func_globals,
-                                              constargs, outerfunc, name)
+                                              constargs, outerfunc, name,
+                                              is_generator)
         graph = ec.graph
         graph.func = func
         # attach a signature and defaults to the graph
@@ -291,6 +291,11 @@
             e = error.FlowingError(formated)
             raise error.FlowingError, e, tb
         checkgraph(graph)
+        #
+        if is_generator and tweak_for_generator:
+            from pypy.translator.generator import tweak_generator_graph
+            tweak_generator_graph(graph)
+        #
         return graph
 
     def fixedview(self, w_tuple, expected_length=None):
diff --git a/pypy/objspace/flow/test/test_generator.py b/pypy/objspace/flow/test/test_generator.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/flow/test/test_generator.py
@@ -0,0 +1,18 @@
+from pypy.objspace.flow.test.test_objspace import Base
+
+
+class TestGenerator(Base):
+
+    def test_simple_generator(self):
+        def f(n):
+            i = 0
+            while i < n:
+                yield i
+                yield i
+                i += 1
+        graph = self.codetest(f, tweak_for_generator=False)
+        ops = self.all_operations(graph)
+        assert ops == {'generator_mark': 1,
+                       'lt': 1, 'is_true': 1,
+                       'yield': 2,
+                       'inplace_add': 1}
diff --git a/pypy/objspace/flow/test/test_objspace.py b/pypy/objspace/flow/test/test_objspace.py
--- a/pypy/objspace/flow/test/test_objspace.py
+++ b/pypy/objspace/flow/test/test_objspace.py
@@ -16,14 +16,14 @@
 is_operator = getattr(operator, 'is_', operator.eq) # it's not there 2.2
 
 class Base:
-    def codetest(self, func):
+    def codetest(self, func, **kwds):
         import inspect
         try:
             func = func.im_func
         except AttributeError:
             pass
         #name = func.func_name
-        graph = self.space.build_flow(func)
+        graph = self.space.build_flow(func, **kwds)
         graph.source = inspect.getsource(func)
         self.show(graph)
         return graph
@@ -882,12 +882,6 @@
                 num = bytecode_spec.opmap[name]
                 flow_meth_names[num] = locals()['old_' + name]
 
-    def test_generator(self):
-        def f():
-            yield 3
-
-        py.test.raises(TypeError, "self.codetest(f)")
-
     def test_dont_capture_RuntimeError(self):
         class Foo:
             def __hash__(self):
diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -514,29 +514,46 @@
     if maxsplit == 0:
         return space.wrap(input)
 
-    # An ok guess at the default size
-    builder = StringBuilder(len(input))
-    first = True
-
     if not sub:
         upper = len(input)
         if maxsplit > 0 and maxsplit < upper + 2:
             upper = maxsplit - 1
             assert upper >= 0
-        first = False
+
         try:
-            for i in range(upper):
-                builder.append(by)
-                builder.append(input[i])
+            result_size = ovfcheck(upper * len(by))
+            result_size = ovfcheck(result_size + upper)
+            result_size = ovfcheck(result_size + len(by))
+            remaining_size = len(input) - upper
+            result_size = ovfcheck(result_size + remaining_size)
+        except OverflowError:
+            raise OperationError(space.w_OverflowError,
+                space.wrap("replace string is too long")
+            )
+        builder = StringBuilder(result_size)
+        for i in range(upper):
             builder.append(by)
-            builder.append_slice(input, upper, len(input))
-        except MemoryError:
+            builder.append(input[i])
+        builder.append(by)
+        builder.append_slice(input, upper, len(input))
+    else:
+        # An ok guess for the result size
+        count = input.count(sub)
+        if count > maxsplit and maxsplit > 0:
+            count = maxsplit
+        diff_len = len(by) - len(sub)
+        try:
+            result_size = ovfcheck(diff_len * count)
+            result_size = ovfcheck(result_size + len(input))
+        except OverflowError:
             raise OperationError(space.w_OverflowError,
-                space.wrap("replace string too long")
+                space.wrap("replace string is too long")
             )
-    else:
+
+        builder = StringBuilder(result_size)
         start = 0
         sublen = len(sub)
+        first = True
 
         while maxsplit != 0:
             next = input.find(sub, start)
diff --git a/pypy/rpython/test/test_generator.py b/pypy/rpython/test/test_generator.py
new file mode 100644
--- /dev/null
+++ b/pypy/rpython/test/test_generator.py
@@ -0,0 +1,62 @@
+from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
+
+
+class BaseTestGenerator(BaseRtypingTest):
+
+    def test_simple_explicit(self):
+        def g(a, b, c):
+            yield a
+            yield b
+            yield c
+        def f():
+            gen = g(3, 5, 8)
+            x = gen.next() * 100
+            x += gen.next() * 10
+            x += gen.next()
+            return x
+        res = self.interpret(f, [])
+        assert res == 358
+
+    def test_cannot_merge(self):
+        # merging two different generators is not supported
+        # right now, but we can use workarounds like here
+        class MyGen:
+            _immutable_ = True
+            def next(self):
+                raise NotImplementedError
+        class MyG1(MyGen):
+            _immutable_ = True
+            def __init__(self, a):
+                self._gen = self.g1(a)
+            def next(self):
+                return self._gen.next()
+            @staticmethod
+            def g1(a):
+                yield a + 1
+                yield a + 2
+        class MyG2(MyGen):
+            _immutable_ = True
+            def __init__(self):
+                self._gen = self.g2()
+            def next(self):
+                return self._gen.next()
+            @staticmethod
+            def g2():
+                yield 42
+        def f(n):
+            if n > 0:
+                gen = MyG1(n)
+            else:
+                gen = MyG2()
+            return gen.next()
+        res = self.interpret(f, [10])
+        assert res == 11
+        res = self.interpret(f, [0])
+        assert res == 42
+
+
+class TestLLtype(BaseTestGenerator, LLRtypeMixin):
+    pass
+
+class TestOOtype(BaseTestGenerator, OORtypeMixin):
+    pass
diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py
--- a/pypy/tool/jitlogparser/parser.py
+++ b/pypy/tool/jitlogparser/parser.py
@@ -3,6 +3,7 @@
 from pypy.jit.metainterp.resoperation import opname
 from pypy.jit.tool.oparser import OpParser
 from pypy.tool.logparser import parse_log_file, extract_category
+from copy import copy
 
 class Op(object):
     bridge = None
@@ -387,6 +388,18 @@
         loops.append(loop)
     return log, loops
 
+def split_trace(trace):
+    labels = [i for i, op in enumerate(trace.operations)
+              if op.name == 'label']
+    labels = [0] + labels + [len(trace.operations) - 1]
+    parts = []
+    for i in range(len(labels) - 1):
+        start, stop = labels[i], labels[i+1]
+        part = copy(trace)
+        part.operations = trace.operations[start : stop + 1]
+        parts.append(part)
+    
+    return parts
 
 def parse_log_counts(input, loops):
     if not input:
diff --git a/pypy/tool/jitlogparser/test/test_modulefinder.py b/pypy/tool/jitlogparser/test/test_modulefinder.py
--- a/pypy/tool/jitlogparser/test/test_modulefinder.py
+++ b/pypy/tool/jitlogparser/test/test_modulefinder.py
@@ -7,12 +7,14 @@
         py.test.skip("Specific python 2.6 tests")
 
 def test_gather_code_py():
+    py.test.skip("XXX broken, fix me")
     fname = re.__file__
     codes = gather_all_code_objs(fname)
     assert len(codes) == 21
     assert sorted(codes.keys()) == [102, 134, 139, 144, 153, 164, 169, 181, 188, 192, 197, 206, 229, 251, 266, 271, 277, 285, 293, 294, 308]
 
 def test_load_code():
+    py.test.skip("XXX broken, fix me")
     fname = re.__file__
     code = gather_all_code_objs(fname)[144]
     assert code.co_name == 'sub'
diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py
--- a/pypy/tool/jitlogparser/test/test_parser.py
+++ b/pypy/tool/jitlogparser/test/test_parser.py
@@ -1,6 +1,6 @@
 from pypy.tool.jitlogparser.parser import (SimpleParser, TraceForOpcode,
                                            Function, adjust_bridges,
-                                           import_log, Op)
+                                           import_log, split_trace, Op)
 from pypy.tool.jitlogparser.storage import LoopStorage
 import py, sys
 
@@ -231,3 +231,21 @@
     myrepr = 'c = foobar(a, b, descr=mydescr)'
     assert op.repr() == myrepr
     assert op.repr() == myrepr # do it twice
+
+def test_split_trace():
+    loop = parse('''
+    [i7]
+    i9 = int_lt(i7, 1003)
+    label(i9)
+    guard_true(i9, descr=<Guard2>) []
+    i13 = getfield_raw(151937600, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>)
+    label(i13)
+    i19 = int_lt(i13, 1003)
+    guard_true(i19, descr=<Guard2>) []
+    i113 = getfield_raw(151937600, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>)
+    ''')
+    parts = split_trace(loop)
+    assert len(parts) == 3
+    assert len(parts[0].operations) == 2
+    assert len(parts[1].operations) == 4
+    assert len(parts[2].operations) == 4
diff --git a/pypy/translator/generator.py b/pypy/translator/generator.py
new file mode 100644
--- /dev/null
+++ b/pypy/translator/generator.py
@@ -0,0 +1,166 @@
+from pypy.objspace.flow.model import Block, Link, SpaceOperation, checkgraph
+from pypy.objspace.flow.model import Variable, Constant, FunctionGraph
+from pypy.translator.unsimplify import insert_empty_startblock
+from pypy.translator.unsimplify import split_block
+from pypy.translator.simplify import eliminate_empty_blocks
+from pypy.tool.sourcetools import func_with_new_name
+from pypy.interpreter.argument import Signature
+
+
+class AbstractPosition(object):
+    _immutable_ = True
+    _attrs_ = ()
+
+
+def tweak_generator_graph(graph):
+    if not hasattr(graph.func, '_generator_next_method_of_'):
+        # This is the first copy of the graph.  We replace it with
+        # a small bootstrap graph.
+        GeneratorIterator = make_generatoriterator_class(graph)
+        replace_graph_with_bootstrap(GeneratorIterator, graph)
+        # We attach a 'next' method to the GeneratorIterator class
+        # that will invoke the real function, based on a second
+        # copy of the graph.
+        attach_next_method(GeneratorIterator, graph)
+    else:
+        # This is the second copy of the graph.  Tweak it.
+        GeneratorIterator = graph.func._generator_next_method_of_
+        tweak_generator_body_graph(GeneratorIterator.Entry, graph)
+
+
+def make_generatoriterator_class(graph):
+    class GeneratorIterator(object):
+        class Entry(AbstractPosition):
+            _immutable_ = True
+            varnames = get_variable_names(graph.startblock.inputargs)
+        def __init__(self, entry):
+            self.current = entry
+    return GeneratorIterator
+
+def replace_graph_with_bootstrap(GeneratorIterator, graph):
+    Entry = GeneratorIterator.Entry
+    newblock = Block(graph.startblock.inputargs)
+    v_generator = Variable('generator')
+    v_entry = Variable('entry')
+    newblock.operations.append(
+        SpaceOperation('simple_call', [Constant(Entry)], v_entry))
+    assert len(graph.startblock.inputargs) == len(Entry.varnames)
+    for v, name in zip(graph.startblock.inputargs, Entry.varnames):
+        newblock.operations.append(
+            SpaceOperation('setattr', [v_entry, Constant(name), v],
+                           Variable()))
+    newblock.operations.append(
+        SpaceOperation('simple_call', [Constant(GeneratorIterator), v_entry],
+                       v_generator))
+    newblock.closeblock(Link([v_generator], graph.returnblock))
+    graph.startblock = newblock
+
+def attach_next_method(GeneratorIterator, graph):
+    func = graph.func
+    func = func_with_new_name(func, '%s__next' % (func.func_name,))
+    func._generator_next_method_of_ = GeneratorIterator
+    func._always_inline_ = True
+    #
+    def next(self):
+        entry = self.current
+        self.current = None
+        (next_entry, return_value) = func(entry)
+        self.current = next_entry
+        return return_value
+    GeneratorIterator.next = next
+    return func   # for debugging
+
+def get_variable_names(variables):
+    seen = set()
+    result = []
+    for v in variables:
+        name = v._name.strip('_')
+        while name in seen:
+            name += '_'
+        result.append('g_' + name)
+        seen.add(name)
+    return result
+
+def _insert_reads(block, varnames):
+    assert len(varnames) == len(block.inputargs)
+    v_entry1 = Variable('entry')
+    for i, name in enumerate(varnames):
+        block.operations.insert(i,
+            SpaceOperation('getattr', [v_entry1, Constant(name)],
+                           block.inputargs[i]))
+    block.inputargs = [v_entry1]
+
+def tweak_generator_body_graph(Entry, graph):
+    assert graph.startblock.operations[0].opname == 'generator_mark'
+    graph.startblock.operations.pop(0)
+    #
+    insert_empty_startblock(None, graph)
+    _insert_reads(graph.startblock, Entry.varnames)
+    Entry.block = graph.startblock
+    #
+    mappings = [Entry]
+    #
+    for block in list(graph.iterblocks()):
+        for exit in block.exits:
+            if exit.target is graph.returnblock:
+                exit.args = [Constant(StopIteration),
+                             Constant(StopIteration())]
+                exit.target = graph.exceptblock
+        for index in range(len(block.operations)-1, -1, -1):
+            op = block.operations[index]
+            if op.opname == 'yield':
+                [v_yielded_value] = op.args
+                del block.operations[index]
+                newlink = split_block(None, block, index)
+                newblock = newlink.target
+                #
+                class Resume(AbstractPosition):
+                    _immutable_ = True
+                    block = newblock
+                Resume.__name__ = 'Resume%d' % len(mappings)
+                mappings.append(Resume)
+                varnames = get_variable_names(newlink.args)
+                #
+                _insert_reads(newblock, varnames)
+                #
+                v_resume = Variable('resume')
+                block.operations.append(
+                    SpaceOperation('simple_call', [Constant(Resume)],
+                                   v_resume))
+                for i, name in enumerate(varnames):
+                    block.operations.append(
+                        SpaceOperation('setattr', [v_resume, Constant(name),
+                                                   newlink.args[i]],
+                                       Variable()))
+                v_pair = Variable('pair')
+                block.operations.append(
+                    SpaceOperation('newtuple', [v_resume, v_yielded_value],
+                                   v_pair))
+                newlink.args = [v_pair]
+                newlink.target = graph.returnblock
+    #
+    regular_entry_block = Block([Variable('entry')])
+    block = regular_entry_block
+    for Resume in mappings:
+        v_check = Variable()
+        block.operations.append(
+            SpaceOperation('simple_call', [Constant(isinstance),
+                                           block.inputargs[0],
+                                           Constant(Resume)],
+                           v_check))
+        block.exitswitch = v_check
+        link1 = Link([block.inputargs[0]], Resume.block)
+        link1.exitcase = True
+        nextblock = Block([Variable('entry')])
+        link2 = Link([block.inputargs[0]], nextblock)
+        link2.exitcase = False
+        block.closeblock(link1, link2)
+        block = nextblock
+    block.closeblock(Link([Constant(AssertionError),
+                           Constant(AssertionError("bad generator class"))],
+                          graph.exceptblock))
+    graph.startblock = regular_entry_block
+    graph.signature = Signature(['entry'])
+    graph.defaults = ()
+    checkgraph(graph)
+    eliminate_empty_blocks(graph)
diff --git a/pypy/translator/test/test_generator.py b/pypy/translator/test/test_generator.py
new file mode 100644
--- /dev/null
+++ b/pypy/translator/test/test_generator.py
@@ -0,0 +1,156 @@
+from pypy.conftest import option
+from pypy.objspace.flow.objspace import FlowObjSpace
+from pypy.objspace.flow.model import Variable
+from pypy.interpreter.argument import Signature
+from pypy.translator.translator import TranslationContext
+from pypy.translator.generator import make_generatoriterator_class
+from pypy.translator.generator import replace_graph_with_bootstrap
+from pypy.translator.generator import get_variable_names
+from pypy.translator.generator import tweak_generator_body_graph
+from pypy.translator.generator import attach_next_method
+from pypy.translator.simplify import join_blocks
+
+
+# ____________________________________________________________
+
+def f_gen(n):
+    i = 0
+    while i < n:
+        yield i
+        i += 1
+
+class GeneratorIterator(object):
+    def __init__(self, entry):
+        self.current = entry
+    def next(self):
+        e = self.current
+        self.current = None
+        if isinstance(e, Yield1):
+            n = e.n_0
+            i = e.i_0
+            i += 1
+        else:
+            n = e.n_0
+            i = 0
+        if i < n:
+            e = Yield1()
+            e.n_0 = n
+            e.i_0 = i
+            self.current = e
+            return i
+        raise StopIteration
+
+    def __iter__(self):
+        return self
+
+class AbstractPosition(object):
+    _immutable_ = True
+class Entry1(AbstractPosition):
+    _immutable_ = True
+class Yield1(AbstractPosition):
+    _immutable_ = True
+
+def f_explicit(n):
+    e = Entry1()
+    e.n_0 = n
+    return GeneratorIterator(e)
+
+def test_explicit():
+    assert list(f_gen(10)) == list(f_explicit(10))
+
+def test_get_variable_names():
+    lst = get_variable_names([Variable('a'), Variable('b_'), Variable('a')])
+    assert lst == ['g_a', 'g_b', 'g_a_']
+
+# ____________________________________________________________
+
+
+class TestGenerator:
+
+    def test_replace_graph_with_bootstrap(self):
+        def func(n, x, y, z):
+            yield n
+            yield n
+        #
+        space = FlowObjSpace()
+        graph = space.build_flow(func, tweak_for_generator=False)
+        assert graph.startblock.operations[0].opname == 'generator_mark'
+        GeneratorIterator = make_generatoriterator_class(graph)
+        replace_graph_with_bootstrap(GeneratorIterator, graph)
+        if option.view:
+            graph.show()
+        block = graph.startblock
+        ops = block.operations
+        assert ops[0].opname == 'simple_call' # e = Entry1()
+        assert ops[1].opname == 'setattr'     # e.g_n = n
+        assert ops[1].args[1].value == 'g_n'
+        assert ops[2].opname == 'setattr'     # e.g_x = x
+        assert ops[2].args[1].value == 'g_x'
+        assert ops[3].opname == 'setattr'     # e.g_y = y
+        assert ops[3].args[1].value == 'g_y'
+        assert ops[4].opname == 'setattr'     # e.g_z = z
+        assert ops[4].args[1].value == 'g_z'
+        assert ops[5].opname == 'simple_call' # g = GeneratorIterator(e)
+        assert ops[5].args[1] == ops[0].result
+        assert len(ops) == 6
+        assert len(block.exits) == 1
+        assert block.exits[0].target is graph.returnblock
+
+    def test_tweak_generator_body_graph(self):
+        def f(n, x, y, z=3):
+            z *= 10
+            yield n + 1
+            z -= 10
+        #
+        space = FlowObjSpace()
+        graph = space.build_flow(f, tweak_for_generator=False)
+        class Entry:
+            varnames = ['g_n', 'g_x', 'g_y', 'g_z']
+        tweak_generator_body_graph(Entry, graph)
+        if option.view:
+            graph.show()
+        # XXX how to test directly that the graph is correct?  :-(
+        assert len(graph.startblock.inputargs) == 1
+        assert graph.signature == Signature(['entry'])
+        assert graph.defaults == ()
+
+    def test_tweak_generator_graph(self):
+        def f(n, x, y, z):
+            z *= 10
+            yield n + 1
+            z -= 10
+        #
+        space = FlowObjSpace()
+        graph = space.build_flow(f, tweak_for_generator=False)
+        GeneratorIterator = make_generatoriterator_class(graph)
+        replace_graph_with_bootstrap(GeneratorIterator, graph)
+        func1 = attach_next_method(GeneratorIterator, graph)
+        if option.view:
+            graph.show()
+        #
+        assert func1._generator_next_method_of_ is GeneratorIterator
+        assert hasattr(GeneratorIterator, 'next')
+        #
+        graph_next = space.build_flow(GeneratorIterator.next.im_func)
+        join_blocks(graph_next)
+        if option.view:
+            graph_next.show()
+        #
+        graph1 = space.build_flow(func1, tweak_for_generator=False)
+        tweak_generator_body_graph(GeneratorIterator.Entry, graph1)
+        if option.view:
+            graph1.show()
+
+    def test_automatic(self):
+        def f(n, x, y, z):
+            z *= 10
+            yield n + 1
+            z -= 10
+        #
+        space = FlowObjSpace()
+        graph = space.build_flow(f)   # tweak_for_generator=True
+        if option.view:
+            graph.show()
+        block = graph.startblock
+        assert len(block.exits) == 1
+        assert block.exits[0].target is graph.returnblock
diff --git a/testrunner/runner.py b/testrunner/runner.py
--- a/testrunner/runner.py
+++ b/testrunner/runner.py
@@ -21,6 +21,16 @@
                 win32api.CloseHandle(proch)
             except pywintypes.error, e:
                 pass
+    #Try to avoid opeing a dialog box if one of the tests causes a system error
+    import ctypes
+    winapi = ctypes.windll.kernel32
+    SEM_FAILCRITICALERRORS = 1
+    SEM_NOGPFAULTERRORBOX  = 2
+    SEM_NOOPENFILEERRORBOX = 0x8000
+    flags = SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX
+    #Since there is no GetErrorMode, do a double Set
+    old_mode = winapi.SetErrorMode(flags)
+    winapi.SetErrorMode(old_mode | flags)
 
     SIGKILL = SIGTERM = 0
     READ_MODE = 'rU'


More information about the pypy-commit mailing list