[pypy-commit] pypy win64-stage1: Merge with default (2 mon)

ctismer noreply at buildbot.pypy.org
Tue Mar 13 00:03:03 CET 2012


Author: Christian Tismer <tismer at stackless.com>
Branch: win64-stage1
Changeset: r53376:d067bda477b7
Date: 2012-03-12 16:02 -0700
http://bitbucket.org/pypy/pypy/changeset/d067bda477b7/

Log:	Merge with default (2 mon)

diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py
--- a/pypy/jit/backend/llsupport/descr.py
+++ b/pypy/jit/backend/llsupport/descr.py
@@ -425,7 +425,15 @@
                 self.arg_classes.count('L')) == len(args_f or ())
 
     def repr_of_descr(self):
-        return '<CallDescr(%s,%s)>' % (self.arg_classes, self.result_type)
+        res = 'Call%s %d' % (self.result_type, self.result_size)
+        if self.arg_classes:
+            res += ' ' + self.arg_classes
+        if self.extrainfo:
+            res += ' EF=%d' % self.extrainfo.extraeffect
+            oopspecindex = self.extrainfo.oopspecindex
+            if oopspecindex:
+                res += ' OS=%d' % oopspecindex
+        return '<%s>' % res
 
 
 def map_type_to_argclass(ARG, accept_void=False):
diff --git a/pypy/jit/backend/llsupport/test/test_descr.py b/pypy/jit/backend/llsupport/test/test_descr.py
--- a/pypy/jit/backend/llsupport/test/test_descr.py
+++ b/pypy/jit/backend/llsupport/test/test_descr.py
@@ -313,6 +313,10 @@
 
 
 def test_repr_of_descr():
+    def repr_of_descr(descr):
+        s = descr.repr_of_descr()
+        assert ',' not in s  # makes the life easier for pypy.tool.jitlogparser
+        return s
     c0 = GcCache(False)
     T = lltype.GcStruct('T')
     S = lltype.GcStruct('S', ('x', lltype.Char),
@@ -320,34 +324,34 @@
                              ('z', lltype.Ptr(T)))
     descr1 = get_size_descr(c0, S)
     s = symbolic.get_size(S, False)
-    assert descr1.repr_of_descr() == '<SizeDescr %d>' % s
+    assert repr_of_descr(descr1) == '<SizeDescr %d>' % s
     #
     descr2 = get_field_descr(c0, S, 'y')
     o, _ = symbolic.get_field_token(S, 'y', False)
-    assert descr2.repr_of_descr() == '<FieldP S.y %d>' % o
+    assert repr_of_descr(descr2) == '<FieldP S.y %d>' % o
     #
     descr2i = get_field_descr(c0, S, 'x')
     o, _ = symbolic.get_field_token(S, 'x', False)
-    assert descr2i.repr_of_descr() == '<FieldU S.x %d>' % o
+    assert repr_of_descr(descr2i) == '<FieldU S.x %d>' % o
     #
     descr3 = get_array_descr(c0, lltype.GcArray(lltype.Ptr(S)))
     o = symbolic.get_size(lltype.Ptr(S), False)
-    assert descr3.repr_of_descr() == '<ArrayP %d>' % o
+    assert repr_of_descr(descr3) == '<ArrayP %d>' % o
     #
     descr3i = get_array_descr(c0, lltype.GcArray(lltype.Char))
-    assert descr3i.repr_of_descr() == '<ArrayU 1>'
+    assert repr_of_descr(descr3i) == '<ArrayU 1>'
     #
     descr4 = get_call_descr(c0, [lltype.Char, lltype.Ptr(S)], lltype.Ptr(S))
-    assert descr4.repr_of_descr() == '<CallDescr(ir,r)>'
+    assert repr_of_descr(descr4) == '<Callr %d ir>' % o
     #
     descr4i = get_call_descr(c0, [lltype.Char, lltype.Ptr(S)], lltype.Char)
-    assert descr4i.repr_of_descr() == '<CallDescr(ir,i)>'
+    assert repr_of_descr(descr4i) == '<Calli 1 ir>'
     #
     descr4f = get_call_descr(c0, [lltype.Char, lltype.Ptr(S)], lltype.Float)
-    assert descr4f.repr_of_descr() == '<CallDescr(ir,f)>'
+    assert repr_of_descr(descr4f) == '<Callf 8 ir>'
     #
     descr5f = get_call_descr(c0, [lltype.Char], lltype.SingleFloat)
-    assert descr5f.repr_of_descr() == '<CallDescr(i,S)>'
+    assert repr_of_descr(descr5f) == '<CallS 4 i>'
 
 def test_call_stubs_1():
     c0 = GcCache(False)
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
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
@@ -105,7 +105,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 +126,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 +185,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 +201,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 +213,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 +751,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 +767,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/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -706,6 +706,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
@@ -713,7 +716,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")
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/memmgr.py b/pypy/jit/metainterp/memmgr.py
--- a/pypy/jit/metainterp/memmgr.py
+++ b/pypy/jit/metainterp/memmgr.py
@@ -1,5 +1,5 @@
 import math
-from pypy.rlib.rarithmetic import r_int64, r_uint
+from pypy.rlib.rarithmetic import r_int64
 from pypy.rlib.debug import debug_start, debug_print, debug_stop
 from pypy.rlib.objectmodel import we_are_translated
 
@@ -21,7 +21,6 @@
 #
 
 class MemoryManager(object):
-    NO_NEXT_CHECK = r_int64(2 ** 63 - 1)
 
     def __init__(self):
         self.check_frequency = -1
@@ -37,13 +36,12 @@
         # According to my estimates it's about 5e9 years given 1000 loops
         # per second
         self.current_generation = r_int64(1)
-        self.next_check = self.NO_NEXT_CHECK
+        self.next_check = r_int64(-1)
         self.alive_loops = {}
-        self._cleanup_jitcell_dicts = lambda: None
 
     def set_max_age(self, max_age, check_frequency=0):
         if max_age <= 0:
-            self.next_check = self.NO_NEXT_CHECK
+            self.next_check = r_int64(-1)
         else:
             self.max_age = max_age
             if check_frequency <= 0:
@@ -51,11 +49,10 @@
             self.check_frequency = check_frequency
             self.next_check = self.current_generation + 1
 
-    def next_generation(self, do_cleanups_now=True):
+    def next_generation(self):
         self.current_generation += 1
-        if do_cleanups_now and self.current_generation >= self.next_check:
+        if self.current_generation == self.next_check:
             self._kill_old_loops_now()
-            self._cleanup_jitcell_dicts()
             self.next_check = self.current_generation + self.check_frequency
 
     def keep_loop_alive(self, looptoken):
@@ -84,22 +81,3 @@
             # a single one is not enough for all tests :-(
             rgc.collect(); rgc.collect(); rgc.collect()
         debug_stop("jit-mem-collect")
-
-    def get_current_generation_uint(self):
-        """Return the current generation, possibly truncated to a uint.
-        To use only as an approximation for decaying counters."""
-        return r_uint(self.current_generation)
-
-    def record_jitcell_dict(self, callback):
-        """NOT_RPYTHON.  The given jitcell_dict is a dict that needs
-        occasional clean-ups of old cells.  A cell is old if it never
-        reached the threshold, and its counter decayed to a tiny value."""
-        # note that the various jitcell_dicts have different RPython types,
-        # so we have to make a different function for each one.  These
-        # functions are chained to each other: each calls the previous one.
-        def cleanup_dict():
-            callback()
-            cleanup_previous()
-        #
-        cleanup_previous = self._cleanup_jitcell_dicts
-        self._cleanup_jitcell_dicts = cleanup_dict
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
@@ -1,3 +1,4 @@
+from __future__ import with_statement
 from pypy.jit.metainterp.optimizeopt.test.test_util import (
     LLtypeMixin, BaseTest, Storage, _sortboxes, FakeDescrWithSnapshot)
 from pypy.jit.metainterp.history import TreeLoop, JitCellToken, TargetToken
@@ -8,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')
@@ -32,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
         
@@ -53,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):
@@ -193,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,76 @@
         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()
-                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!!!
+                assert newresult is op.result or newvalue.is_constant()
         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 +280,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 +291,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 +318,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 +326,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 +378,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 +392,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 +408,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 +423,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 +450,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 +549,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 +566,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 +579,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
@@ -46,7 +46,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:
@@ -59,7 +59,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
 
@@ -75,7 +76,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)
@@ -104,7 +105,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'
@@ -137,7 +138,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
@@ -218,12 +219,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)
@@ -270,7 +271,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)
@@ -287,7 +288,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,
@@ -362,7 +363,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))
@@ -370,7 +371,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
@@ -436,10 +438,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):
@@ -456,7 +461,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()
@@ -466,7 +471,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):
@@ -476,8 +481,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)
@@ -596,8 +604,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
@@ -626,15 +634,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)
@@ -670,7 +678,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
 
@@ -2062,7 +2057,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:
@@ -2072,13 +2067,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)
@@ -2090,7 +2085,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)
@@ -2102,7 +2097,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
@@ -2110,43 +2105,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_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -2910,27 +2910,6 @@
         res = self.meta_interp(f, [32])
         assert res == f(32)
 
-    def test_decay_counters(self):
-        myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
-        def f(m, n):
-            while n > 0:
-                myjitdriver.jit_merge_point(m=m, n=n)
-                n += m
-                n -= m
-                n -= 1
-        def main():
-            f(5, 7)      # run 7x with m=5           counter[m=5] = 7
-            f(15, 10)    # compiles one loop         counter[m=5] = 3  (automatic decay)
-            f(5, 5)      # run 5x times with m=5     counter[m=5] = 8
-        #
-        self.meta_interp(main, [], decay_halflife=1,
-                         function_threshold=0, threshold=9, trace_eagerness=99)
-        self.check_trace_count(1)
-        #
-        self.meta_interp(main, [], decay_halflife=1,
-                         function_threshold=0, threshold=8, trace_eagerness=99)
-        self.check_trace_count(2)
-
 
 class TestOOtype(BasicTests, OOJitMixin):
 
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/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py
--- a/pypy/jit/metainterp/test/test_warmstate.py
+++ b/pypy/jit/metainterp/test/test_warmstate.py
@@ -1,4 +1,3 @@
-import math
 from pypy.rpython.test.test_llinterp import interpret
 from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi
 from pypy.rpython.ootypesystem import ootype
@@ -9,7 +8,7 @@
 from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr
 from pypy.jit.metainterp.history import ConstInt, ConstFloat, ConstPtr
 from pypy.jit.codewriter import longlong
-from pypy.rlib.rarithmetic import r_singlefloat, r_uint
+from pypy.rlib.rarithmetic import r_singlefloat
 
 def boxfloat(x):
     return BoxFloat(longlong.getfloatstorage(x))
@@ -277,76 +276,51 @@
     res = state.can_never_inline(5, 42.5)
     assert res is True
 
-def test_decay_counters():
-    cell = JitCell(r_uint(5))
-    cell.counter = 100
-    cell.adjust_counter(r_uint(5), math.log(0.9))
-    assert cell.counter == 100
-    cell.adjust_counter(r_uint(6), math.log(0.9))
-    assert cell.counter == 90
-    cell.adjust_counter(r_uint(9), math.log(0.9))
-    assert cell.counter == int(90 * (0.9**3))
-
 def test_cleanup_jitcell_dict():
-    from pypy.jit.metainterp.memmgr import MemoryManager
-    class FakeWarmRunnerDesc:
-        memory_manager = MemoryManager()
-        class cpu:
-            pass
     class FakeJitDriverSD:
         _green_args_spec = [lltype.Signed]
     #
     # Test creating tons of jitcells that remain at 0
-    warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
+    warmstate = WarmEnterState(None, FakeJitDriverSD())
     get_jitcell = warmstate._make_jitcell_getter_default()
     cell1 = get_jitcell(True, -1)
     assert len(warmstate._jitcell_dict) == 1
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 1
     #
     for i in range(1, 20005):
         get_jitcell(True, i)     # should trigger a clean-up at 20001
         assert len(warmstate._jitcell_dict) == (i % 20000) + 1
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 2
     #
     # Same test, with one jitcell that has a counter of BASE instead of 0
-    warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
-    warmstate.set_param_decay_halflife(2)
-    warmstate.set_param_threshold(5)
-    warmstate.set_param_function_threshold(0)
+    warmstate = WarmEnterState(None, FakeJitDriverSD())
     get_jitcell = warmstate._make_jitcell_getter_default()
     cell2 = get_jitcell(True, -2)
-    cell2.counter = BASE = warmstate.increment_threshold * 3
+    cell2.counter = BASE = warmstate.THRESHOLD_LIMIT // 2    # 50%
     #
     for i in range(0, 20005):
         get_jitcell(True, i)
         assert len(warmstate._jitcell_dict) == (i % 19999) + 2
     #
     assert cell2 in warmstate._jitcell_dict.values()
-    assert cell2.counter == int(BASE * math.sqrt(0.5))   # decayed once
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 3
+    assert cell2.counter == int(BASE * 0.92)   # decayed once
     #
-    # Same test, with jitcells that are compiled and free by the memmgr
-    warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
+    # Same test, with jitcells that are compiled and freed by the memmgr
+    warmstate = WarmEnterState(None, FakeJitDriverSD())
     get_jitcell = warmstate._make_jitcell_getter_default()
     get_jitcell(True, -1)
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 3
     #
     for i in range(1, 20005):
         cell = get_jitcell(True, i)
         cell.counter = -1
         cell.wref_procedure_token = None    # or a dead weakref, equivalently
         assert len(warmstate._jitcell_dict) == (i % 20000) + 1
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 4
     #
     # Same test, with counter == -2 (rare case, kept alive)
-    warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
+    warmstate = WarmEnterState(None, FakeJitDriverSD())
     get_jitcell = warmstate._make_jitcell_getter_default()
     cell = get_jitcell(True, -1)
     cell.counter = -2
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 4
     #
     for i in range(1, 20005):
         cell = get_jitcell(True, i)
         cell.counter = -2
         assert len(warmstate._jitcell_dict) == i + 1
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 5
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -64,11 +64,9 @@
 
 def jittify_and_run(interp, graph, args, repeat=1, graph_and_interp_only=False,
                     backendopt=False, trace_limit=sys.maxint,
-                    threshold=3, trace_eagerness=2,
                     inline=False, loop_longevity=0, retrace_limit=5,
-                    function_threshold=4, decay_halflife=0,
-                    enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15,
-                    **kwds):
+                    function_threshold=4,
+                    enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15, **kwds):
     from pypy.config.config import ConfigError
     translator = interp.typer.annotator.translator
     try:
@@ -85,16 +83,15 @@
         pass
     warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds)
     for jd in warmrunnerdesc.jitdrivers_sd:
-        jd.warmstate.set_param_threshold(threshold)
+        jd.warmstate.set_param_threshold(3)          # for tests
         jd.warmstate.set_param_function_threshold(function_threshold)
-        jd.warmstate.set_param_trace_eagerness(trace_eagerness)
+        jd.warmstate.set_param_trace_eagerness(2)    # for tests
         jd.warmstate.set_param_trace_limit(trace_limit)
         jd.warmstate.set_param_inlining(inline)
         jd.warmstate.set_param_loop_longevity(loop_longevity)
         jd.warmstate.set_param_retrace_limit(retrace_limit)
         jd.warmstate.set_param_max_retrace_guards(max_retrace_guards)
         jd.warmstate.set_param_enable_opts(enable_opts)
-        jd.warmstate.set_param_decay_halflife(decay_halflife)
     warmrunnerdesc.finish()
     if graph_and_interp_only:
         return interp, graph
diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py
--- a/pypy/jit/metainterp/warmstate.py
+++ b/pypy/jit/metainterp/warmstate.py
@@ -1,10 +1,10 @@
-import sys, weakref, math
+import sys, weakref
 from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.annlowlevel import hlstr, cast_base_ptr_to_instance
 from pypy.rpython.annlowlevel import cast_object_to_ptr
 from pypy.rlib.objectmodel import specialize, we_are_translated, r_dict
-from pypy.rlib.rarithmetic import intmask, r_uint
+from pypy.rlib.rarithmetic import intmask
 from pypy.rlib.nonconst import NonConstant
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.jit import PARAMETERS
@@ -151,27 +151,9 @@
     #     counter == -2: tracing is currently going on for this cell
     counter = 0
     dont_trace_here = False
+    extra_delay = chr(0)
     wref_procedure_token = None
 
-    def __init__(self, generation):
-        # The stored 'counter' value follows an exponential decay model.
-        # Conceptually after every generation, it decays by getting
-        # multiplied by a constant <= 1.0.  In practice, decaying occurs
-        # lazily: the following field records the latest seen generation
-        # number, and adjustment is done by adjust_counter() when needed.
-        self.latest_generation_seen = generation
-
-    def adjust_counter(self, generation, log_decay_factor):
-        if generation != self.latest_generation_seen:
-            # The latest_generation_seen is older than the current generation.
-            # Adjust by multiplying self.counter N times by decay_factor, i.e.
-            # by decay_factor ** N, which is equal to exp(log(decay_factor)*N).
-            assert self.counter >= 0
-            N = generation - self.latest_generation_seen
-            factor = math.exp(log_decay_factor * N)
-            self.counter = int(self.counter * factor)
-            self.latest_generation_seen = generation
-
     def get_procedure_token(self):
         if self.wref_procedure_token is not None:
             token = self.wref_procedure_token()
@@ -231,17 +213,6 @@
     def set_param_inlining(self, value):
         self.inlining = value
 
-    def set_param_decay_halflife(self, value):
-        # Use 0 or -1 to mean "no decay".  Initialize the internal variable
-        # 'log_decay_factor'.  It is choosen such that by multiplying the
-        # counter on loops by 'exp(log_decay_factor)' (<= 1.0) every
-        # generation, then the counter will be divided by two after 'value'
-        # generations have passed.
-        if value <= 0:
-            self.log_decay_factor = 0.0    # log(1.0)
-        else:
-            self.log_decay_factor = math.log(0.5) / value
-
     def set_param_enable_opts(self, value):
         from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT, ALL_OPTS_NAMES
 
@@ -311,11 +282,6 @@
         confirm_enter_jit = self.confirm_enter_jit
         range_red_args = unrolling_iterable(
             range(num_green_args, num_green_args + jitdriver_sd.num_red_args))
-        memmgr = self.warmrunnerdesc.memory_manager
-        if memmgr is not None:
-            get_current_generation = memmgr.get_current_generation_uint
-        else:
-            get_current_generation = lambda: r_uint(0)
         # get a new specialized copy of the method
         ARGS = []
         for kind in jitdriver_sd.red_args_types:
@@ -350,6 +316,36 @@
             #
             assert 0, "should have raised"
 
+        def bound_reached(cell, *args):
+            # bound reached, but we do a last check: if it is the first
+            # time we reach the bound, or if another loop or bridge was
+            # compiled since the last time we reached it, then decrease
+            # the counter by a few percents instead.  It should avoid
+            # sudden bursts of JIT-compilation, and also corner cases
+            # where we suddenly compile more than one loop because all
+            # counters reach the bound at the same time, but where
+            # compiling all but the first one is pointless.
+            curgen = warmrunnerdesc.memory_manager.current_generation
+            curgen = chr(intmask(curgen) & 0xFF)    # only use 8 bits
+            if we_are_translated() and curgen != cell.extra_delay:
+                cell.counter = int(self.THRESHOLD_LIMIT * 0.98)
+                cell.extra_delay = curgen
+                return
+            #
+            if not confirm_enter_jit(*args):
+                cell.counter = 0
+                return
+            # start tracing
+            from pypy.jit.metainterp.pyjitpl import MetaInterp
+            metainterp = MetaInterp(metainterp_sd, jitdriver_sd)
+            # set counter to -2, to mean "tracing in effect"
+            cell.counter = -2
+            try:
+                metainterp.compile_and_run_once(jitdriver_sd, *args)
+            finally:
+                if cell.counter == -2:
+                    cell.counter = 0
+
         def maybe_compile_and_run(threshold, *args):
             """Entry point to the JIT.  Called at the point with the
             can_enter_jit() hint.
@@ -360,25 +356,13 @@
 
             if cell.counter >= 0:
                 # update the profiling counter
-                cell.adjust_counter(get_current_generation(),
-                                    self.log_decay_factor)
                 n = cell.counter + threshold
                 if n <= self.THRESHOLD_LIMIT:       # bound not reached
                     cell.counter = n
                     return
-                if not confirm_enter_jit(*args):
-                    cell.counter = 0
+                else:
+                    bound_reached(cell, *args)
                     return
-                # bound reached; start tracing
-                from pypy.jit.metainterp.pyjitpl import MetaInterp
-                metainterp = MetaInterp(metainterp_sd, jitdriver_sd)
-                # set counter to -2, to mean "tracing in effect"
-                cell.counter = -2
-                try:
-                    metainterp.compile_and_run_once(jitdriver_sd, *args)
-                finally:
-                    if cell.counter == -2:
-                        cell.counter = 0
             else:
                 if cell.counter != -1:
                     assert cell.counter == -2
@@ -454,15 +438,6 @@
         #
         return jit_getter
 
-    def _new_jitcell(self):
-        warmrunnerdesc = self.warmrunnerdesc
-        if (warmrunnerdesc is not None and
-                warmrunnerdesc.memory_manager is not None):
-            gen = warmrunnerdesc.memory_manager.get_current_generation_uint()
-        else:
-            gen = r_uint(0)
-        return JitCell(gen)
-
     def _make_jitcell_getter_default(self):
         "NOT_RPYTHON"
         jitdriver_sd = self.jitdriver_sd
@@ -492,44 +467,32 @@
         except AttributeError:
             pass
         #
-        memmgr = self.warmrunnerdesc and self.warmrunnerdesc.memory_manager
-        if memmgr:
-            def _cleanup_dict():
-                minimum = sys.maxint
-                if self.increment_threshold > 0:
-                    minimum = min(minimum, self.increment_threshold)
-                if self.increment_function_threshold > 0:
-                    minimum = min(minimum, self.increment_function_threshold)
-                currentgen = memmgr.get_current_generation_uint()
-                killme = []
-                for key, cell in jitcell_dict.iteritems():
-                    if cell.counter >= 0:
-                        cell.adjust_counter(currentgen, self.log_decay_factor)
-                        if cell.counter < minimum:
-                            killme.append(key)
-                    elif (cell.counter == -1
-                          and cell.get_procedure_token() is None):
+        def _cleanup_dict():
+            minimum = self.THRESHOLD_LIMIT // 20     # minimum 5%
+            killme = []
+            for key, cell in jitcell_dict.iteritems():
+                if cell.counter >= 0:
+                    cell.counter = int(cell.counter * 0.92)
+                    if cell.counter < minimum:
                         killme.append(key)
-                for key in killme:
-                    del jitcell_dict[key]
-            #
-            def _maybe_cleanup_dict():
-                # If no tracing goes on at all because the jitcells are
-                # each time for new greenargs, the dictionary grows forever.
-                # So every one in a (rare) while, we decide to force an
-                # artificial next_generation() and _cleanup_dict().
-                self._trigger_automatic_cleanup += 1
-                if self._trigger_automatic_cleanup > 20000:
-                    self._trigger_automatic_cleanup = 0
-                    memmgr.next_generation(do_cleanups_now=False)
-                    _cleanup_dict()
-            #
-            self._trigger_automatic_cleanup = 0
-            self._jitcell_dict = jitcell_dict       # for tests
-            memmgr.record_jitcell_dict(_cleanup_dict)
-        else:
-            def _maybe_cleanup_dict():
-                pass
+                elif (cell.counter == -1
+                      and cell.get_procedure_token() is None):
+                    killme.append(key)
+            for key in killme:
+                del jitcell_dict[key]
+        #
+        def _maybe_cleanup_dict():
+            # Once in a while, rarely, when too many entries have
+            # been put in the jitdict_dict, we do a cleanup phase:
+            # we decay all counters and kill entries with a too
+            # low counter.
+            self._trigger_automatic_cleanup += 1
+            if self._trigger_automatic_cleanup > 20000:
+                self._trigger_automatic_cleanup = 0
+                _cleanup_dict()
+        #
+        self._trigger_automatic_cleanup = 0
+        self._jitcell_dict = jitcell_dict       # for tests
         #
         def get_jitcell(build, *greenargs):
             try:
@@ -538,7 +501,7 @@
                 if not build:
                     return None
                 _maybe_cleanup_dict()
-                cell = self._new_jitcell()
+                cell = JitCell()
                 jitcell_dict[greenargs] = cell
             return cell
         return get_jitcell
@@ -549,7 +512,7 @@
         get_jitcell_at_ptr = self.jitdriver_sd._get_jitcell_at_ptr
         set_jitcell_at_ptr = self.jitdriver_sd._set_jitcell_at_ptr
         lltohlhack = {}
-        # note that there is no equivalent of record_jitcell_dict()
+        # note that there is no equivalent of _maybe_cleanup_dict()
         # in the case of custom getters.  We assume that the interpreter
         # stores the JitCells on some objects that can go away by GC,
         # like the PyCode objects in PyPy.
@@ -574,7 +537,7 @@
             if not build:
                 return cell
             if cell is None:
-                cell = self._new_jitcell()
+                cell = JitCell()
                 # <hacks>
                 if we_are_translated():
                     cellref = cast_object_to_ptr(BASEJITCELL, cell)
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
@@ -319,6 +319,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/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/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,104 @@
+
+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
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
 
 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.copy()
+
+    def copy(self):
         return self.get_concrete().copy()
 
     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,417 @@
             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()
+            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 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):
+        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 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 +854,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 +869,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 +905,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 +929,55 @@
             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
 
-    @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))]
+class ViewArray(ConcreteArray):
+    def copy(self):
+        array = W_NDimArray(self.size, self.shape[:], self.find_dtype())
+        iter = view_iter_from_arr(self)
+        a_iter = ArrayIterator(array.size)
+        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 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 create_sig(self, res_shape):
+        return signature.ViewSignature(self.dtype)
 
-    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)
 
-    @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)
-
-    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
+        ViewArray.__init__(self, size, shape, parent.dtype, parent.order,
+                               parent)
+        self.start = start
 
-    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 setslice(self, space, w_value):
+        res_shape = shape_agreement(space, self.shape, w_value.shape)
+        self._sliceloop(w_value, res_shape)
 
-    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)
+    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 setshape(self, space, new_shape):
         if len(self.shape) < 1:
@@ -1220,96 +1013,10 @@
         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(
@@ -1319,32 +1026,16 @@
         )
         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 +1087,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 +1184,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_
@@ -1075,10 +1086,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 +1123,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 +1192,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/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py
--- a/pypy/module/pypyjit/test_pypy_c/model.py
+++ b/pypy/module/pypyjit/test_pypy_c/model.py
@@ -311,7 +311,7 @@
         # to repeat it every time
         ticker_check = """
             guard_not_invalidated?
-            ticker0 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+            ticker0 = getfield_raw(ticker_address, descr=<FieldS pypysig_long_struct.c_value .*>)
             ticker_cond0 = int_lt(ticker0, 0)
             guard_false(ticker_cond0, descr=...)
         """
@@ -320,9 +320,9 @@
         # this is the ticker check generated if we have threads
         thread_ticker_check = """
             guard_not_invalidated?
-            ticker0 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+            ticker0 = getfield_raw(ticker_address, descr=<FieldS pypysig_long_struct.c_value .*>)
             ticker1 = int_sub(ticker0, _)
-            setfield_raw(ticker_address, ticker1, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+            setfield_raw(ticker_address, ticker1, descr=<FieldS pypysig_long_struct.c_value .*>)
             ticker_cond0 = int_lt(ticker1, 0)
             guard_false(ticker_cond0, descr=...)
         """
@@ -330,7 +330,7 @@
         #
         # this is the ticker check generated in PyFrame.handle_operation_error
         exc_ticker_check = """
-            ticker2 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+            ticker2 = getfield_raw(ticker_address, descr=<FieldS pypysig_long_struct.c_value .*>)
             ticker_cond1 = int_lt(ticker2, 0)
             guard_false(ticker_cond1, descr=...)
         """
@@ -451,7 +451,6 @@
         try:
             self.match_loop(expected_ops, ignore_ops)
         except InvalidMatch, e:
-            #raise # uncomment this and use py.test --pdb for better debugging
             print '@' * 40
             print "Loops don't match"
             print "================="
@@ -464,7 +463,7 @@
             print
             print "Expected:"
             print format(expected_src)
-            return False
+            raise     # always propagate the exception in case of mismatch
         else:
             return True
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
@@ -7,8 +7,9 @@
 from pypy.tool.udir import udir
 from pypy.tool import logparser
 from pypy.jit.tool.jitoutput import parse_prof
-from pypy.module.pypyjit.test_pypy_c.model import Log, find_ids_range, find_ids, \
-    TraceWithIds, OpMatcher
+from pypy.module.pypyjit.test_pypy_c.model import (Log, find_ids_range,
+                                                   find_ids, TraceWithIds,
+                                                   OpMatcher, InvalidMatch)
 
 class BaseTestPyPyC(object):
     def setup_class(cls):
@@ -115,13 +116,18 @@
         assert opcodes_names == ['LOAD_FAST', 'LOAD_CONST', 'BINARY_ADD', 'STORE_FAST']
 
 
-class TestOpMatcher(object):
+class TestOpMatcher_(object):
 
     def match(self, src1, src2, **kwds):
         from pypy.tool.jitlogparser.parser import SimpleParser
         loop = SimpleParser.parse_from_input(src1)
         matcher = OpMatcher(loop.operations)
-        return matcher.match(src2, **kwds)
+        try:
+            res = matcher.match(src2, **kwds)
+            assert res is True
+            return True
+        except InvalidMatch:
+            return False
 
     def test_match_var(self):
         match_var = OpMatcher([]).match_var
@@ -447,7 +453,7 @@
             jump(p0, p1, p2, p3, i8, descr=...)
         """)
         #
-        assert not loop.match("""
+        py.test.raises(InvalidMatch, loop.match, """
             i6 = int_lt(i4, 1003)
             guard_true(i6)
             i8 = int_add(i5, 1) # variable mismatch
@@ -492,9 +498,8 @@
             guard_no_exception(descr=...)
         """)
         #
-        assert not loop.match_by_id('ntohs', """
+        py.test.raises(InvalidMatch, loop.match_by_id, 'ntohs', """
             guard_not_invalidated(descr=...)
             p12 = call(ConstClass(foobar), 1, descr=...)
             guard_no_exception(descr=...)
         """)
-        
diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
@@ -35,7 +35,7 @@
             guard_not_invalidated(descr=...)
             i17 = force_token()
             setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>)
-            f21 = call_release_gil(%s, 2.000000, 3.000000, descr=<FloatCallDescr>)
+            f21 = call_release_gil(%s, 2.000000, 3.000000, descr=<Callf 8 ff EF=6>)
             guard_not_forced(descr=...)
             guard_no_exception(descr=...)
         """ % pow_addr)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py
--- a/pypy/module/pypyjit/test_pypy_c/test_array.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_array.py
@@ -42,7 +42,7 @@
             guard_not_invalidated(descr=...)
             i13 = int_lt(i7, i9)
             guard_true(i13, descr=...)
-            i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>)
+            i15 = getarrayitem_raw(i10, i7, descr=<ArrayS .>)
             i16 = int_add_ovf(i8, i15)
             guard_no_overflow(descr=...)
             i18 = int_add(i7, 1)
@@ -72,17 +72,17 @@
             guard_true(i13, descr=...)
             guard_not_invalidated(descr=...)
         # the bound check guard on img has been killed (thanks to the asserts)
-            i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>)
+            i14 = getarrayitem_raw(i10, i8, descr=<ArrayS .>)
             i15 = int_add_ovf(i9, i14)
             guard_no_overflow(descr=...)
             i17 = int_sub(i8, 640)
         # the bound check guard on intimg has been killed (thanks to the asserts)
-            i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>)
+            i18 = getarrayitem_raw(i11, i17, descr=<ArrayS .>)
             i19 = int_add_ovf(i18, i15)
             guard_no_overflow(descr=...)
         # on 64bit, there is a guard checking that i19 actually fits into 32bit
             ...
-            setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>)
+            setarrayitem_raw(i11, i8, _, descr=<ArrayS .>)
             i28 = int_add(i8, 1)
             --TICK--
             jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=...)
@@ -107,10 +107,10 @@
             guard_true(i10, descr=...)
             i11 = int_lt(i6, i7)
             guard_true(i11, descr=...)
-            f13 = getarrayitem_raw(i8, i6, descr=<FloatArrayNoLengthDescr>)
+            f13 = getarrayitem_raw(i8, i6, descr=<ArrayF 8>)
             f15 = float_add(f13, 20.500000)
-            setarrayitem_raw(i8, i6, f15, descr=<FloatArrayNoLengthDescr>)
-            f16 = getarrayitem_raw(i8, i6, descr=<FloatArrayNoLengthDescr>)
+            setarrayitem_raw(i8, i6, f15, descr=<ArrayF 8>)
+            f16 = getarrayitem_raw(i8, i6, descr=<ArrayF 8>)
             i18 = float_eq(f16, 42.000000)
             guard_true(i18, descr=...)
             i20 = int_add(i6, 1)
@@ -132,28 +132,24 @@
         log = self.run(main, [])
         assert log.result == 321
         loop, = log.loops_by_filename(self.filepath)
-        if sys.maxint == 2147483647:
-            arraydescr = 'UnsignedArrayNoLengthDescr'
-        else:
-            arraydescr = 'UINTArrayNoLengthDescr'
         assert loop.match("""
             i10 = int_lt(i6, 1000)
             guard_true(i10, descr=...)
             i11 = int_lt(i6, i7)
             guard_true(i11, descr=...)
-            i13 = getarrayitem_raw(i8, i6, descr=<%s>)
+            i13 = getarrayitem_raw(i8, i6, descr=<Array. 4>)
             f14 = cast_singlefloat_to_float(i13)
             f16 = float_add(f14, 20.500000)
             i17 = cast_float_to_singlefloat(f16)
-            setarrayitem_raw(i8, i6,i17, descr=<%s>)
-            i18 = getarrayitem_raw(i8, i6, descr=<%s>)
+            setarrayitem_raw(i8, i6,i17, descr=<Array. 4>)
+            i18 = getarrayitem_raw(i8, i6, descr=<Array. 4>)
             f19 = cast_singlefloat_to_float(i18)
             i21 = float_eq(f19, 42.000000)
             guard_true(i21, descr=...)
             i23 = int_add(i6, 1)
             --TICK--
             jump(..., descr=...)
-        """ % (arraydescr, arraydescr, arraydescr))
+        """)
 
 
     def test_zeropadded(self):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -75,12 +75,12 @@
         assert log.opnames(ops) == []
         #
         assert entry_bridge.match_by_id('call', """
-            p38 = call(ConstClass(getexecutioncontext), descr=<GcPtrCallDescr>)
-            p39 = getfield_gc(p38, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
+            p38 = call(ConstClass(getexecutioncontext), descr=<Callr . EF=1>)
+            p39 = getfield_gc(p38, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
             i40 = force_token()
-            p41 = getfield_gc(p38, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
+            p41 = getfield_gc(p38, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
             guard_isnull(p41, descr=...)
-            i42 = getfield_gc(p38, descr=<NonGcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
+            i42 = getfield_gc(p38, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
             i43 = int_is_zero(i42)
             guard_true(i43, descr=...)
             i50 = force_token()
@@ -192,7 +192,7 @@
         assert log.result == 1000
         loop, = log.loops_by_id('call')
         assert loop.match_by_id('call', """
-            p14 = getarrayitem_gc_pure(p8, i9, descr=<GcPtrArrayDescr>)
+            p14 = getarrayitem_gc_pure(p8, i9, descr=<ArrayP .>)
             i14 = force_token()
             i16 = force_token()
         """)
@@ -336,15 +336,15 @@
         loop, = log.loops_by_filename(self.filepath)
         # the int strategy is used here
         assert loop.match_by_id('append', """
-            i13 = getfield_gc(p8, descr=<SignedFieldDescr list.length .*>)
+            i13 = getfield_gc(p8, descr=<FieldS list.length .*>)
             i15 = int_add(i13, 1)
             # Will be killed by the backend
-            p15 = getfield_gc(p8, descr=<GcPtrFieldDescr list.items .*>)
-            i17 = arraylen_gc(p15, descr=<SignedArrayDescr>)
-            call(_, p8, i15, descr=<VoidCallDescr>) # this is a call to _ll_list_resize_ge_trampoline__...
+            p15 = getfield_gc(p8, descr=<FieldP list.items .*>)
+            i17 = arraylen_gc(p15, descr=<ArrayS .>)
+            call(_, p8, i15, descr=<Callv 0 ri EF=4>) # this is a call to _ll_list_resize_ge_trampoline__...
             guard_no_exception(descr=...)
-            p17 = getfield_gc(p8, descr=<GcPtrFieldDescr list.items .*>)
-            setarrayitem_gc(p17, i13, i12, descr=<SignedArrayDescr>)
+            p17 = getfield_gc(p8, descr=<FieldP list.items .*>)
+            setarrayitem_gc(p17, i13, i12, descr=<ArrayS .>)
         """)
 
     def test_blockstack_virtualizable(self):
@@ -368,13 +368,13 @@
             ...
             i20 = force_token()
             p22 = new_with_vtable(19511408)
-            p24 = new_array(1, descr=<GcPtrArrayDescr>)
+            p24 = new_array(1, descr=<ArrayP .>)
             p26 = new_with_vtable(ConstClass(W_ListObject))
-            setfield_gc(p0, i20, descr=<SignedFieldDescr .*PyFrame.vable_token .*>)
-            setfield_gc(p26, ConstPtr(ptr22), descr=<GcPtrFieldDescr pypy.objspace.std.listobject.W_ListObject.inst_strategy .*>)
-            setarrayitem_gc(p24, 0, p26, descr=<GcPtrArrayDescr>)
-            setfield_gc(p22, p24, descr=<GcPtrFieldDescr .*Arguments.inst_arguments_w .*>)
-            p32 = call_may_force(11376960, p18, p22, descr=<GcPtrCallDescr>)
+            setfield_gc(p0, i20, descr=<FieldS .*PyFrame.vable_token .*>)
+            setfield_gc(p26, ConstPtr(ptr22), descr=<FieldP pypy.objspace.std.listobject.W_ListObject.inst_strategy .*>)
+            setarrayitem_gc(p24, 0, p26, descr=<ArrayP .>)
+            setfield_gc(p22, p24, descr=<FieldP .*Arguments.inst_arguments_w .*>)
+            p32 = call_may_force(11376960, p18, p22, descr=<Callr . rr EF=6>)
             ...
         """)
 
@@ -415,26 +415,26 @@
             guard_nonnull_class(p8, ConstClass(W_IntObject), descr=...)
             guard_value(i4, 0, descr=...)
             guard_value(p3, ConstPtr(ptr14), descr=...)
-            i15 = getfield_gc_pure(p8, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+            i15 = getfield_gc_pure(p8, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
             i17 = int_lt(i15, 5000)
             guard_true(i17, descr=...)
-            p18 = getfield_gc(p0, descr=<GcPtrFieldDescr pypy.interpreter.eval.Frame.inst_w_globals .*>)
+            p18 = getfield_gc(p0, descr=<FieldP pypy.interpreter.eval.Frame.inst_w_globals .*>)
             guard_value(p18, ConstPtr(ptr19), descr=...)
-            p20 = getfield_gc(p18, descr=<GcPtrFieldDescr pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_strategy .*>)
+            p20 = getfield_gc(p18, descr=<FieldP pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_strategy .*>)
             guard_value(p20, ConstPtr(ptr21), descr=...)
             guard_not_invalidated(descr=...)
             # most importantly, there is no getarrayitem_gc here
-            p23 = call(ConstClass(getexecutioncontext), descr=<GcPtrCallDescr>)
-            p24 = getfield_gc(p23, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
+            p23 = call(ConstClass(getexecutioncontext), descr=<Callr . EF=1>)
+            p24 = getfield_gc(p23, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
             i25 = force_token()
-            p26 = getfield_gc(p23, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
+            p26 = getfield_gc(p23, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
             guard_isnull(p26, descr=...)
-            i27 = getfield_gc(p23, descr=<NonGcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
+            i27 = getfield_gc(p23, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
             i28 = int_is_zero(i27)
             guard_true(i28, descr=...)
-            p30 = getfield_gc(ConstPtr(ptr29), descr=<GcPtrFieldDescr pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
+            p30 = getfield_gc(ConstPtr(ptr29), descr=<FieldP pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
             guard_nonnull_class(p30, ConstClass(W_IntObject), descr=...)
-            i32 = getfield_gc_pure(p30, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+            i32 = getfield_gc_pure(p30, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
             i33 = int_add_ovf(i15, i32)
             guard_no_overflow(descr=...)
             --TICK--
@@ -452,15 +452,15 @@
             """, [])
         loop, = log.loops_by_id('call')
         assert loop.match("""
-            i8 = getfield_gc_pure(p6, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+            i8 = getfield_gc_pure(p6, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
             i10 = int_lt(i8, 5000)
             guard_true(i10, descr=...)
             i11 = force_token()
             i13 = int_add(i8, 1)
             --TICK--
             p22 = new_with_vtable(ConstClass(W_IntObject))
-            setfield_gc(p22, i13, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
-            setfield_gc(p4, p22, descr=<GcPtrFieldDescr pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
+            setfield_gc(p22, i13, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+            setfield_gc(p4, p22, descr=<FieldP pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
             jump(p0, p1, p2, p3, p4, p7, p22, p7, descr=...)
         """)
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_containers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py
@@ -46,7 +46,7 @@
         assert loop.match_by_id("getitem", """
             i26 = call(ConstClass(ll_dict_lookup), p18, p6, i25, descr=...)
             ...
-            p33 = getinteriorfield_gc(p31, i26, descr=<InteriorFieldDescr <GcPtrFieldDescr dictentry.value .*>>)
+            p33 = getinteriorfield_gc(p31, i26, descr=<InteriorFieldDescr <FieldP dictentry.value .*>>)
             ...
         """)
 
@@ -86,28 +86,28 @@
             i8 = int_lt(i5, i7)
             guard_true(i8, descr=...)
             guard_not_invalidated(descr=...)
-            p10 = call(ConstClass(ll_int_str), i5, descr=<GcPtrCallDescr>)
+            p10 = call(ConstClass(ll_int_str), i5, descr=<Callr . i EF=3>)
             guard_no_exception(descr=...)
-            i12 = call(ConstClass(ll_strhash), p10, descr=<SignedCallDescr>)
+            i12 = call(ConstClass(ll_strhash), p10, descr=<Calli . r EF=0>)
             p13 = new(descr=...)
-            p15 = new_array(8, descr=<dictentryArrayDescr>)
-            setfield_gc(p13, p15, descr=<GcPtrFieldDescr dicttable.entries .*>)
-            i17 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<SignedCallDescr>)
-            setfield_gc(p13, 16, descr=<SignedFieldDescr dicttable.resize_counter .*>)
+            p15 = new_array(8, descr=<ArrayX .*>)
+            setfield_gc(p13, p15, descr=<FieldP dicttable.entries .*>)
+            i17 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<Calli . rri EF=4>)
+            setfield_gc(p13, 16, descr=<FieldS dicttable.resize_counter .*>)
             guard_no_exception(descr=...)
             p20 = new_with_vtable(ConstClass(W_IntObject))
-            call(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=<VoidCallDescr>)
-            setfield_gc(p20, i5, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
+            call(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=<Callv 0 rrrii EF=4>)
+            setfield_gc(p20, i5, descr=<FieldS .*W_IntObject.inst_intval .*>)
             guard_no_exception(descr=...)
-            i23 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<SignedCallDescr>)
+            i23 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<Calli . rri EF=4>)
             guard_no_exception(descr=...)
             i26 = int_and(i23, .*)
             i27 = int_is_true(i26)
             guard_false(i27, descr=...)
-            p28 = getfield_gc(p13, descr=<GcPtrFieldDescr dicttable.entries .*>)
-            p29 = getinteriorfield_gc(p28, i23, descr=<InteriorFieldDescr <GcPtrFieldDescr dictentry.value .*>>)
+            p28 = getfield_gc(p13, descr=<FieldP dicttable.entries .*>)
+            p29 = getinteriorfield_gc(p28, i23, descr=<InteriorFieldDescr <FieldP dictentry.value .*>>)
             guard_nonnull_class(p29, ConstClass(W_IntObject), descr=...)
-            i31 = getfield_gc_pure(p29, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
+            i31 = getfield_gc_pure(p29, descr=<FieldS .*W_IntObject.inst_intval .*>)
             i32 = int_sub_ovf(i31, i5)
             guard_no_overflow(descr=...)
             i34 = int_add_ovf(i32, 1)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py
--- a/pypy/module/pypyjit/test_pypy_c/test_generators.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py
@@ -21,9 +21,9 @@
         assert loop.match_by_id("generator", """
             i16 = force_token()
             p45 = new_with_vtable(ConstClass(W_IntObject))
-            setfield_gc(p45, i29, descr=<SignedFieldDescr .*>)
-            setarrayitem_gc(p8, 0, p45, descr=<GcPtrArrayDescr>)
-            i47 = arraylen_gc(p8, descr=<GcPtrArrayDescr>) # Should be removed by backend
+            setfield_gc(p45, i29, descr=<FieldS .*>)
+            setarrayitem_gc(p8, 0, p45, descr=<ArrayP .>)
+            i47 = arraylen_gc(p8, descr=<ArrayP .>) # Should be removed by backend
             jump(..., descr=...)
             """)
         assert loop.match_by_id("subtract", """
diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py
--- a/pypy/module/pypyjit/test_pypy_c/test_globals.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py
@@ -16,11 +16,11 @@
         assert log.result == 500
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match_by_id("loadglobal", """
-            p10 = getfield_gc(p0, descr=<GcPtrFieldDescr .*Frame.inst_w_globals .*>)
+            p10 = getfield_gc(p0, descr=<FieldP .*Frame.inst_w_globals .*>)
             guard_value(p10, ConstPtr(ptr11), descr=...)
-            p12 = getfield_gc(p10, descr=<GcPtrFieldDescr .*W_DictMultiObject.inst_strategy .*>)
+            p12 = getfield_gc(p10, descr=<FieldP .*W_DictMultiObject.inst_strategy .*>)
             guard_value(p12, ConstPtr(ptr13), descr=...)
             guard_not_invalidated(descr=...)
-            p19 = getfield_gc(ConstPtr(p17), descr=<GcPtrFieldDescr .*W_DictMultiObject.inst_strategy .*>)
+            p19 = getfield_gc(ConstPtr(p17), descr=<FieldP .*W_DictMultiObject.inst_strategy .*>)
             guard_value(p19, ConstPtr(ptr20), descr=...)
-        """)
\ No newline at end of file
+        """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py
--- a/pypy/module/pypyjit/test_pypy_c/test_instance.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py
@@ -125,8 +125,8 @@
             i12 = force_token()
             --TICK--
             p20 = new_with_vtable(ConstClass(W_IntObject))
-            setfield_gc(p20, i11, descr=<SignedFieldDescr.*W_IntObject.inst_intval .*>)
-            setfield_gc(ConstPtr(ptr21), p20, descr=<GcPtrFieldDescr .*TypeCell.inst_w_value .*>)
+            setfield_gc(p20, i11, descr=<FieldS.*W_IntObject.inst_intval .*>)
+            setfield_gc(ConstPtr(ptr21), p20, descr=<FieldP .*TypeCell.inst_w_value .*>)
             jump(p0, p1, p2, p3, p4, p20, p6, i7, p20, descr=...)
         """)
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py
--- a/pypy/module/pypyjit/test_pypy_c/test_math.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_math.py
@@ -23,8 +23,8 @@
             f1 = cast_int_to_float(i0)
             i3 = float_le(f1, 0)
             guard_false(i3, descr=...)
-            f2 = call(ConstClass(log), f1, descr=<FloatCallDescr>)
-            f3 = call(ConstClass(log10), f1, descr=<FloatCallDescr>)
+            f2 = call(ConstClass(log), f1, descr=<Callf . f EF=2>)
+            f3 = call(ConstClass(log10), f1, descr=<Callf . f EF=2>)
             f4 = float_sub(f2, f3)
             f5 = float_add(f0, f4)
             i4 = int_add(i0, 1)
@@ -52,8 +52,8 @@
             f1 = cast_int_to_float(i0)
             i6 = --ISINF--(f1)
             guard_false(i6, descr=...)
-            f2 = call(ConstClass(sin), f1, descr=<FloatCallDescr>)
-            f3 = call(ConstClass(cos), f1, descr=<FloatCallDescr>)
+            f2 = call(ConstClass(sin), f1, descr=<Callf . f EF=2>)
+            f3 = call(ConstClass(cos), f1, descr=<Callf . f EF=2>)
             f4 = float_sub(f2, f3)
             f5 = float_add(f0, f4)
             i7 = int_add(i0, f1)
@@ -84,7 +84,7 @@
             i4 = int_or(i2, i3)
             i5 = int_is_true(i4)
             guard_false(i5, descr=...)
-            f2 = call(ConstClass(fmod), f1, 2.0, descr=<FloatCallDescr>)
+            f2 = call(ConstClass(fmod), f1, 2.0, descr=<Callf . ff EF=2>)
             f3 = float_add(f0, f2)
             i6 = int_sub(i0, 1)
             --TICK--
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -46,7 +46,7 @@
                 r *= n
                 n -= 1
             return r
-        log = self.run(fact, [7], threshold=5)
+        log = self.run(fact, [7], threshold=4)
         assert log.result == 5040
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
@@ -204,18 +204,18 @@
         assert log.result == 1000000
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
-            i14 = getfield_gc(p12, descr=<SignedFieldDescr list.length .*>)
+            i14 = getfield_gc(p12, descr=<FieldS list.length .*>)
             i16 = uint_ge(i12, i14)
             guard_false(i16, descr=...)
-            p16 = getfield_gc(p12, descr=<GcPtrFieldDescr list.items .*>)
-            p17 = getarrayitem_gc(p16, i12, descr=<GcPtrArrayDescr>)
+            p16 = getfield_gc(p12, descr=<FieldP list.items .*>)
+            p17 = getarrayitem_gc(p16, i12, descr=<ArrayP .>)
             i19 = int_add(i12, 1)
-            setfield_gc(p9, i19, descr=<SignedFieldDescr .*W_AbstractSeqIterObject.inst_index .*>)
+            setfield_gc(p9, i19, descr=<FieldS .*W_AbstractSeqIterObject.inst_index .*>)
             guard_nonnull_class(p17, 146982464, descr=...)
-            i21 = getfield_gc(p17, descr=<SignedFieldDescr .*W_ArrayTypei.inst_len .*>)
+            i21 = getfield_gc(p17, descr=<FieldS .*W_ArrayTypei.inst_len .*>)
             i23 = int_lt(0, i21)
             guard_true(i23, descr=...)
-            i24 = getfield_gc(p17, descr=<NonGcPtrFieldDescr .*W_ArrayTypei.inst_buffer .*>)
+            i24 = getfield_gc(p17, descr=<FieldU .*W_ArrayTypei.inst_buffer .*>)
             i25 = getarrayitem_raw(i24, 0, descr=<.*>)
             i27 = int_lt(1, i21)
             guard_false(i27, descr=...)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py
--- a/pypy/module/pypyjit/test_pypy_c/test_string.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_string.py
@@ -1,6 +1,9 @@
 from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
 
 
+# XXX review the <Call> descrs to replace some EF=4 with EF=3 (elidable)
+
+
 class TestString(BaseTestPyPyC):
     def test_lookup_default_encoding(self):
         def main(n):
@@ -52,8 +55,8 @@
                 i += int(long(string.digits[i % len(string.digits)], 16))
             return i
 
-        log = self.run(main, [1000])
-        assert log.result == main(1000)
+        log = self.run(main, [1100])
+        assert log.result == main(1100)
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
             i11 = int_lt(i6, i7)
@@ -72,7 +75,7 @@
             i23 = strgetitem(p10, i19)
             p25 = newstr(1)
             strsetitem(p25, 0, i23)
-            p28 = call(ConstClass(strip_spaces), p25, descr=<GcPtrCallDescr>)
+            p28 = call(ConstClass(strip_spaces), p25, descr=<Callr . r EF=4>)
             guard_no_exception(descr=...)
             i29 = strlen(p28)
             i30 = int_is_true(i29)
@@ -88,9 +91,9 @@
             guard_false(i41, descr=...)
             i43 = int_eq(i39, 43)
             guard_false(i43, descr=...)
-            i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=<BoolCallDescr>)
+            i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=<Calli 1 rr EF=0>)
             guard_false(i43, descr=...)
-            i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=<BoolCallDescr>)
+            i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=<Calli 1 rr EF=0>)
             guard_false(i46, descr=...)
             p51 = new_with_vtable(21136408)
             setfield_gc(p51, _, descr=...)    # 7 setfields, but the order is dict-order-dependent
@@ -100,9 +103,9 @@
             setfield_gc(p51, _, descr=...)
             setfield_gc(p51, _, descr=...)
             setfield_gc(p51, _, descr=...)
-            p55 = call(ConstClass(parse_digit_string), p51, descr=<GcPtrCallDescr>)
+            p55 = call(ConstClass(parse_digit_string), p51, descr=<Callr . r EF=4>)
             guard_no_exception(descr=...)
-            i57 = call(ConstClass(rbigint.toint), p55, descr=<SignedCallDescr>)
+            i57 = call(ConstClass(rbigint.toint), p55, descr=<Calli . r EF=3>)
             guard_no_exception(descr=...)
             i58 = int_add_ovf(i6, i57)
             guard_no_overflow(descr=...)
@@ -125,7 +128,7 @@
             i7 = int_gt(i4, 0)
             guard_true(i7, descr=...)
             guard_not_invalidated(descr=...)
-            p9 = call(ConstClass(ll_int2dec__Signed), i4, descr=<GcPtrCallDescr>)
+            p9 = call(ConstClass(ll_int2dec__Signed), i4, descr=<Callr . i EF=3>)
             guard_no_exception(descr=...)
             i10 = strlen(p9)
             i11 = int_is_true(i10)
@@ -149,7 +152,7 @@
             copystrcontent(p9, p21, 0, i25, i10)
             i33 = int_lt(i30, 23)
             guard_true(i33, descr=...)
-            p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=<GcPtrCallDescr>)
+            p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=<Callr . ri EF=4>)
             guard_no_exception(descr=...)
             i37 = strlen(p35)
             i38 = int_add_ovf(i5, i37)
@@ -192,6 +195,6 @@
             strsetitem(p35, 3, 104)
             strsetitem(p35, 4, 95)
             copystrcontent(p31, p35, 0, 5, i32)
-            i49 = call(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=<SignedCallDescr>)
-            guard_value(i49, 1, descr=<Guard8>)
+            i49 = call(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=<Calli [48] rr EF=0 OS=28>)
+            guard_value(i49, 1, descr=...)
             ''')
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/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -514,29 +514,34 @@
     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:
-            raise OperationError(space.w_OverflowError,
-                space.wrap("replace string too long")
-            )
+            builder.append(input[i])
+        builder.append(by)
+        builder.append_slice(input, upper, len(input))
     else:
+        # An ok guess for the result size
+        builder = StringBuilder(len(input))
         start = 0
         sublen = len(sub)
+        first = True
 
         while maxsplit != 0:
             next = input.find(sub, start)
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -395,7 +395,6 @@
               'retrace_limit': 5,
               'max_retrace_guards': 15,
               'enable_opts': 'all',
-              'decay_halflife': 40,
               }
 unroll_parameters = unrolling_iterable(PARAMETERS.items())
 DEFAULT = object()
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