[pypy-commit] pypy op_malloc_gc: hg merge default

arigo noreply at buildbot.pypy.org
Mon Nov 28 11:57:56 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: op_malloc_gc
Changeset: r49892:b5153823527e
Date: 2011-11-28 11:57 +0100
http://bitbucket.org/pypy/pypy/changeset/b5153823527e/

Log:	hg merge default

diff too long, truncating to 10000 out of 12902 lines

diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -1,3 +1,4 @@
 b590cf6de4190623aad9aa698694c22e614d67b9 release-1.5
 b48df0bf4e75b81d98f19ce89d4a7dc3e1dab5e5 benchmarked
 d8ac7d23d3ec5f9a0fa1264972f74a010dbfd07f release-1.6
+ff4af8f318821f7f5ca998613a60fca09aa137da release-1.7
diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py
--- a/lib_pypy/_sqlite3.py
+++ b/lib_pypy/_sqlite3.py
@@ -231,6 +231,9 @@
 sqlite.sqlite3_result_text.argtypes = [c_void_p, c_char_p, c_int, c_void_p]
 sqlite.sqlite3_result_text.restype = None
 
+sqlite.sqlite3_enable_load_extension.argtypes = [c_void_p, c_int]
+sqlite.sqlite3_enable_load_extension.restype = c_int
+
 ##########################################
 # END Wrapped SQLite C API and constants
 ##########################################
@@ -705,6 +708,14 @@
         from sqlite3.dump import _iterdump
         return _iterdump(self)
 
+    def enable_load_extension(self, enabled):
+        self._check_thread()
+        self._check_closed()
+
+        rc = sqlite.sqlite3_enable_load_extension(self.db, int(enabled))
+        if rc != SQLITE_OK:
+            raise OperationalError("Error enabling load extension")
+
 DML, DQL, DDL = range(3)
 
 class Cursor(object):
diff --git a/py/_code/code.py b/py/_code/code.py
--- a/py/_code/code.py
+++ b/py/_code/code.py
@@ -307,7 +307,7 @@
                     self._striptext = 'AssertionError: '
         self._excinfo = tup
         self.type, self.value, tb = self._excinfo
-        self.typename = self.type.__name__
+        self.typename = getattr(self.type, "__name__", "???")
         self.traceback = py.code.Traceback(tb)
 
     def __repr__(self):
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -281,6 +281,9 @@
                    "actually create the full list until the resulting "
                    "list is mutated",
                    default=False),
+        BoolOption("withliststrategies",
+                   "enable optimized ways to store lists of primitives ",
+                   default=True),
 
         BoolOption("withtypeversion",
                    "version type objects when changing them",
diff --git a/pypy/config/test/test_translationoption.py b/pypy/config/test/test_translationoption.py
new file mode 100644
--- /dev/null
+++ b/pypy/config/test/test_translationoption.py
@@ -0,0 +1,10 @@
+import py
+from pypy.config.translationoption import get_combined_translation_config
+from pypy.config.translationoption import set_opt_level
+from pypy.config.config import ConflictConfigError
+
+
+def test_no_gcrootfinder_with_boehm():
+    config = get_combined_translation_config()
+    config.translation.gcrootfinder = "shadowstack"
+    py.test.raises(ConflictConfigError, set_opt_level, config, '0')
diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -69,8 +69,8 @@
                      "statistics": [("translation.gctransformer", "framework")],
                      "generation": [("translation.gctransformer", "framework")],
                      "hybrid": [("translation.gctransformer", "framework")],
-                     "boehm": [("translation.gctransformer", "boehm"),
-                               ("translation.continuation", False)],  # breaks
+                     "boehm": [("translation.continuation", False),  # breaks
+                               ("translation.gctransformer", "boehm")],
                      "markcompact": [("translation.gctransformer", "framework")],
                      "minimark": [("translation.gctransformer", "framework")],
                      },
@@ -398,6 +398,10 @@
     # make_sure_not_resized often relies on it, so we always enable them
     config.translation.suggest(list_comprehension_operations=True)
 
+    # finally, make the choice of the gc definitive.  This will fail
+    # if we have specified strange inconsistent settings.
+    config.translation.gc = config.translation.gc
+
 # ----------------------------------------------------------------
 
 def set_platform(config):
diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst
--- a/pypy/doc/coding-guide.rst
+++ b/pypy/doc/coding-guide.rst
@@ -270,7 +270,12 @@
   - *slicing*:
     the slice start must be within bounds. The stop doesn't need to, but it must
     not be smaller than the start.  All negative indexes are disallowed, except for
-    the [:-1] special case.  No step.
+    the [:-1] special case.  No step.  Slice deletion follows the same rules.
+    
+  - *slice assignment*:
+    only supports ``lst[x:y] = sublist``, if ``len(sublist) == y - x``.
+    In other words, slice assignment cannot change the total length of the list,
+    but just replace items.
 
   - *other operators*:
     ``+``, ``+=``, ``in``, ``*``, ``*=``, ``==``, ``!=`` work as expected.
diff --git a/pypy/doc/config/objspace.std.withliststrategies.txt b/pypy/doc/config/objspace.std.withliststrategies.txt
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/objspace.std.withliststrategies.txt
@@ -0,0 +1,2 @@
+Enable list strategies: Use specialized representations for lists of primitive
+objects, such as ints.
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -262,6 +262,26 @@
 documented as such (as e.g. for hasattr()), in most cases PyPy
 lets the exception propagate instead.
 
+Object Identity of Primitive Values, ``is`` and ``id``
+-------------------------------------------------------
+
+Object identity of primitive values works by value equality, not by identity of
+the wrapper. This means that ``x + 1 is x + 1`` is always true, for arbitrary
+integers ``x``. The rule applies for the following types:
+
+ - ``int``
+
+ - ``float``
+
+ - ``long``
+
+ - ``complex``
+
+This change requires some changes to ``id`` as well. ``id`` fulfills the
+following condition: ``x is y <=> id(x) == id(y)``. Therefore ``id`` of the
+above types will return a value that is computed from the argument, and can
+thus be larger than ``sys.maxint`` (i.e. it can be an arbitrary long).
+
 
 Miscellaneous
 -------------
@@ -284,14 +304,5 @@
   never a dictionary as it sometimes is in CPython. Assigning to
   ``__builtins__`` has no effect.
 
-* Do not compare immutable objects with ``is``.  For example on CPython
-  it is true that ``x is 0`` works, i.e. does the same as ``type(x) is
-  int and x == 0``, but it is so by accident.  If you do instead
-  ``x is 1000``, then it stops working, because 1000 is too large and
-  doesn't come from the internal cache.  In PyPy it fails to work in
-  both cases, because we have no need for a cache at all.
-
-* Also, object identity of immutable keys in dictionaries is not necessarily
-  preserved.
 
 .. include:: _ref.txt
diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst
--- a/pypy/doc/how-to-release.rst
+++ b/pypy/doc/how-to-release.rst
@@ -1,6 +1,3 @@
-.. include:: needswork.txt
-
-.. needs work, it talks about svn. also, it is not really user documentation
 
 Making a PyPy Release
 =======================
@@ -12,11 +9,8 @@
 forgetting things. A set of todo files may also work.
 
 Check and prioritize all issues for the release, postpone some if necessary,
-create new  issues also as necessary. A meeting (or meetings) should be
-organized to decide what things are priorities, should go in and work for
-the release. 
-
-An important thing is to get the documentation into an up-to-date state!
+create new  issues also as necessary. An important thing is to get
+the documentation into an up-to-date state!
 
 Release Steps
 ----------------
diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst
--- a/pypy/doc/project-ideas.rst
+++ b/pypy/doc/project-ideas.rst
@@ -23,17 +23,20 @@
 PyPy's implementation of the Python ``long`` type is slower than CPython's.
 Find out why and optimize them.
 
+Make bytearray type fast
+------------------------
+
+PyPy's bytearray type is very inefficient. It would be an interesting
+task to look into possible optimizations on this.
+
 Numpy improvements
 ------------------
 
-This is more of a project-container than a single project. Possible ideas:
+The numpy is rapidly progressing in pypy, so feel free to come to IRC and
+ask for proposed topic. A not necesarilly up-to-date `list of topics`_
+is also available.
 
-* experiment with auto-vectorization using SSE or implement vectorization
-  without automatically detecting it for array operations.
-
-* improve numpy, for example implement memory views.
-
-* interface with fortran/C libraries.
+.. _`list of topics`: https://bitbucket.org/pypy/extradoc/src/extradoc/planning/micronumpy.txt
 
 Improving the jitviewer
 ------------------------
diff --git a/pypy/doc/release-1.7.0.rst b/pypy/doc/release-1.7.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-1.7.0.rst
@@ -0,0 +1,94 @@
+==================================
+PyPy 1.7 - widening the sweet spot
+==================================
+
+We're pleased to announce the 1.7 release of PyPy. As became a habit, this
+release brings a lot of bugfixes and performance improvements over the 1.6
+release. However, unlike the previous releases, the focus has been on widening
+the "sweet spot" of PyPy. That is, classes of Python code that PyPy can greatly
+speed up should be vastly improved with this release. You can download the 1.7
+release here:
+
+    http://pypy.org/download.html
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 1.7 and cpython 2.7.1`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 32/64 or
+Windows 32. Windows 64 work is ongoing, but not yet natively supported.
+
+The main topic of this release is widening the range of code which PyPy
+can greatly speed up. On average on
+our benchmark suite, PyPy 1.7 is around **30%** faster than PyPy 1.6 and up
+to **20 times** faster on some benchmarks.
+
+.. _`pypy 1.7 and cpython 2.7.1`: http://speed.pypy.org
+
+
+Highlights
+==========
+
+* Numerous performance improvements. There are too many examples which python
+  constructs now should behave faster to list them.
+
+* Bugfixes and compatibility fixes with CPython.
+
+* Windows fixes.
+
+* PyPy now comes with stackless features enabled by default. However,
+  any loop using stackless features will interrupt the JIT for now, so no real
+  performance improvement for stackless-based programs. Contact pypy-dev for
+  info how to help on removing this restriction.
+
+* NumPy effort in PyPy was renamed numpypy. In order to try using it, simply
+  write::
+
+    import numpypy as numpy
+
+  at the beginning of your program. There is a huge progress on numpy in PyPy
+  since 1.6, the main feature being implementation of dtypes.
+
+* JSON encoder (but not decoder) has been replaced with a new one. This one
+  is written in pure Python, but is known to outperform CPython's C extension
+  up to **2 times** in some cases. It's about **20 times** faster than
+  the one that we had in 1.6.
+
+* The memory footprint of some of our RPython modules has been drastically
+  improved. This should impact any applications using for example cryptography,
+  like tornado.
+
+* There was some progress in exposing even more CPython C API via cpyext.
+
+Things that didn't make it, expect in 1.8 soon
+==============================================
+
+There is an ongoing work, which while didn't make it to the release, is
+probably worth mentioning here. This is what you should probably expect in
+1.8 some time soon:
+
+* Specialized list implementation. There is a branch that implements lists of
+  integers/floats/strings as compactly as array.array. This should drastically
+  improve performance/memory impact of some applications
+
+* NumPy effort is progressing forward, with multi-dimensional arrays coming
+  soon.
+
+* There are two brand new JIT assembler backends, notably for the PowerPC and
+  ARM processors.
+
+Fundraising
+===========
+
+It's maybe worth mentioning that we're running fundraising campaigns for
+NumPy effort in PyPy and for Python 3 in PyPy. In case you want to see any
+of those happen faster, we urge you to donate to `numpy proposal`_ or
+`py3k proposal`_. In case you want PyPy to progress, but you trust us with
+the general direction, you can always donate to the `general pot`_.
+
+.. _`numpy proposal`: http://pypy.org/numpydonate.html
+.. _`py3k proposal`: http://pypy.org/py3donate.html
+.. _`general pot`: http://pypy.org
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -188,6 +188,12 @@
 
     # -------------------------------------------------------------------
 
+    def is_w(self, space, w_other):
+        return self is w_other
+
+    def unique_id(self, space):
+        return space.wrap(compute_unique_id(self))
+
     def str_w(self, space):
         w_msg = typed_unwrap_error_msg(space, "string", self)
         raise OperationError(space.w_TypeError, w_msg)
@@ -681,9 +687,17 @@
         """shortcut for space.is_true(space.eq(w_obj1, w_obj2))"""
         return self.is_w(w_obj1, w_obj2) or self.is_true(self.eq(w_obj1, w_obj2))
 
-    def is_w(self, w_obj1, w_obj2):
-        """shortcut for space.is_true(space.is_(w_obj1, w_obj2))"""
-        return self.is_true(self.is_(w_obj1, w_obj2))
+    def is_(self, w_one, w_two):
+        return self.newbool(self.is_w(w_one, w_two))
+
+    def is_w(self, w_one, w_two):
+        # done by a method call on w_two (and not on w_one, because of the
+        # expected programming style where we say "if x is None" or
+        # "if x is object").
+        return w_two.is_w(self, w_one)
+
+    def id(self, w_obj):
+        return w_obj.unique_id(self)
 
     def hash_w(self, w_obj):
         """shortcut for space.int_w(space.hash(w_obj))"""
@@ -879,6 +893,16 @@
         """
         return self.unpackiterable(w_iterable, expected_length)
 
+    def listview_str(self, w_list):
+        """ Return a list of unwrapped strings out of a list of strings. If the
+        argument is not a list or does not contain only strings, return None.
+        May return None anyway.
+        """
+        return None
+
+    def newlist_str(self, list_s):
+        return self.newlist([self.wrap(s) for s in list_s])
+
     @jit.unroll_safe
     def exception_match(self, w_exc_type, w_check_class):
         """Checks if the given exception type matches 'w_check_class'."""
@@ -1013,9 +1037,6 @@
     def isinstance_w(self, w_obj, w_type):
         return self.is_true(self.isinstance(w_obj, w_type))
 
-    def id(self, w_obj):
-        return self.wrap(compute_unique_id(w_obj))
-
     # The code below only works
     # for the simple case (new-style instance).
     # These methods are patched with the full logic by the __builtin__
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -1,8 +1,9 @@
+from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.error import OperationError
-from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.gateway import NoneNotWrapped
+from pypy.interpreter.pyopcode import LoopBlock
 from pypy.rlib import jit
-from pypy.interpreter.pyopcode import LoopBlock
+from pypy.rlib.objectmodel import specialize
 
 
 class GeneratorIterator(Wrappable):
@@ -156,38 +157,43 @@
                     break
                 block = block.previous
 
-    def unpack_into(self, results_w):
-        """This is a hack for performance: runs the generator and collects
-        all produced items in a list."""
-        # XXX copied and simplified version of send_ex()
-        space = self.space
-        if self.running:
-            raise OperationError(space.w_ValueError,
-                                 space.wrap('generator already executing'))
-        frame = self.frame
-        if frame is None:    # already finished
-            return
-        self.running = True
-        try:
-            pycode = self.pycode
-            while True:
-                jitdriver.jit_merge_point(self=self, frame=frame,
-                                          results_w=results_w,
-                                          pycode=pycode)
-                try:
-                    w_result = frame.execute_frame(space.w_None)
-                except OperationError, e:
-                    if not e.match(space, space.w_StopIteration):
-                        raise
-                    break
-                # if the frame is now marked as finished, it was RETURNed from
-                if frame.frame_finished_execution:
-                    break
-                results_w.append(w_result)     # YIELDed
-        finally:
-            frame.f_backref = jit.vref_None
-            self.running = False
-            self.frame = None
-
-jitdriver = jit.JitDriver(greens=['pycode'],
-                          reds=['self', 'frame', 'results_w'])
+    # Results can be either an RPython list of W_Root, or it can be an
+    # app-level W_ListObject, which also has an append() method, that's why we
+    # generate 2 versions of the function and 2 jit drivers.
+    def _create_unpack_into():
+        jitdriver = jit.JitDriver(greens=['pycode'],
+                                  reds=['self', 'frame', 'results'])
+        def unpack_into(self, results):
+            """This is a hack for performance: runs the generator and collects
+            all produced items in a list."""
+            # XXX copied and simplified version of send_ex()
+            space = self.space
+            if self.running:
+                raise OperationError(space.w_ValueError,
+                                     space.wrap('generator already executing'))
+            frame = self.frame
+            if frame is None:    # already finished
+                return
+            self.running = True
+            try:
+                pycode = self.pycode
+                while True:
+                    jitdriver.jit_merge_point(self=self, frame=frame,
+                                              results=results, pycode=pycode)
+                    try:
+                        w_result = frame.execute_frame(space.w_None)
+                    except OperationError, e:
+                        if not e.match(space, space.w_StopIteration):
+                            raise
+                        break
+                    # if the frame is now marked as finished, it was RETURNed from
+                    if frame.frame_finished_execution:
+                        break
+                    results.append(w_result)     # YIELDed
+            finally:
+                frame.f_backref = jit.vref_None
+                self.running = False
+                self.frame = None
+        return unpack_into
+    unpack_into = _create_unpack_into()
+    unpack_into_w = _create_unpack_into()
\ No newline at end of file
diff --git a/pypy/interpreter/test/test_function.py b/pypy/interpreter/test/test_function.py
--- a/pypy/interpreter/test/test_function.py
+++ b/pypy/interpreter/test/test_function.py
@@ -587,7 +587,7 @@
         assert isinstance(meth2, Method)
         assert meth2.call_args(args) == obj1
         # Check method returned from unbound_method.__get__()
-        w_meth3 = descr_function_get(space, func, None, space.type(obj2))
+        w_meth3 = descr_function_get(space, func, space.w_None, space.type(obj2))
         meth3 = space.unwrap(w_meth3)
         w_meth4 = meth3.descr_method_get(obj2, space.w_None)
         meth4 = space.unwrap(w_meth4)
diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py
--- a/pypy/interpreter/test/test_objspace.py
+++ b/pypy/interpreter/test/test_objspace.py
@@ -63,10 +63,13 @@
     def test_unpackiterable(self):
         space = self.space
         w = space.wrap
-        l = [w(1), w(2), w(3), w(4)]
+        l = [space.newlist([]) for l in range(4)]
         w_l = space.newlist(l)
-        assert space.unpackiterable(w_l) == l
-        assert space.unpackiterable(w_l, 4) == l
+        l1 = space.unpackiterable(w_l)
+        l2 = space.unpackiterable(w_l, 4)
+        for i in range(4):
+            assert space.is_w(l1[i], l[i])
+            assert space.is_w(l2[i], l[i])
         err = raises(OperationError, space.unpackiterable, w_l, 3)
         assert err.value.match(space, space.w_ValueError)
         err = raises(OperationError, space.unpackiterable, w_l, 5)
diff --git a/pypy/jit/backend/conftest.py b/pypy/jit/backend/conftest.py
--- a/pypy/jit/backend/conftest.py
+++ b/pypy/jit/backend/conftest.py
@@ -12,7 +12,7 @@
                     help="choose a fixed random seed")
     group.addoption('--backend', action="store",
                     default='llgraph',
-                    choices=['llgraph', 'x86'],
+                    choices=['llgraph', 'cpu'],
                     dest="backend",
                     help="select the backend to run the functions with")
     group.addoption('--block-length', action="store", type="int",
diff --git a/pypy/jit/backend/test/test_random.py b/pypy/jit/backend/test/test_random.py
--- a/pypy/jit/backend/test/test_random.py
+++ b/pypy/jit/backend/test/test_random.py
@@ -495,9 +495,9 @@
     if pytest.config.option.backend == 'llgraph':
         from pypy.jit.backend.llgraph.runner import LLtypeCPU
         return LLtypeCPU(None)
-    elif pytest.config.option.backend == 'x86':
-        from pypy.jit.backend.x86.runner import CPU386
-        return CPU386(None, None)
+    elif pytest.config.option.backend == 'cpu':
+        from pypy.jit.backend.detect_cpu import getcpuclass
+        return getcpuclass()(None, None)
     else:
         assert 0, "unknown backend %r" % pytest.config.option.backend
 
diff --git a/pypy/jit/backend/x86/test/test_zll_random.py b/pypy/jit/backend/test/test_zll_stress.py
rename from pypy/jit/backend/x86/test/test_zll_random.py
rename to pypy/jit/backend/test/test_zll_stress.py
diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py
--- a/pypy/jit/backend/x86/test/test_ztranslation.py
+++ b/pypy/jit/backend/x86/test/test_ztranslation.py
@@ -1,6 +1,6 @@
 import py, os, sys
 from pypy.tool.udir import udir
-from pypy.rlib.jit import JitDriver, unroll_parameters
+from pypy.rlib.jit import JitDriver, unroll_parameters, set_param
 from pypy.rlib.jit import PARAMETERS, dont_look_inside
 from pypy.rlib.jit import promote
 from pypy.jit.metainterp.jitprof import Profiler
@@ -47,9 +47,9 @@
         def f(i, j):
             for param, _ in unroll_parameters:
                 defl = PARAMETERS[param]
-                jitdriver.set_param(param, defl)
-            jitdriver.set_param("threshold", 3)
-            jitdriver.set_param("trace_eagerness", 2)
+                set_param(jitdriver, param, defl)
+            set_param(jitdriver, "threshold", 3)
+            set_param(jitdriver, "trace_eagerness", 2)
             total = 0
             frame = Frame(i)
             while frame.i > 3:
@@ -213,8 +213,8 @@
             else:
                 return Base()
         def myportal(i):
-            jitdriver.set_param("threshold", 3)
-            jitdriver.set_param("trace_eagerness", 2)
+            set_param(jitdriver, "threshold", 3)
+            set_param(jitdriver, "trace_eagerness", 2)
             total = 0
             n = i
             while True:
diff --git a/pypy/jit/codewriter/codewriter.py b/pypy/jit/codewriter/codewriter.py
--- a/pypy/jit/codewriter/codewriter.py
+++ b/pypy/jit/codewriter/codewriter.py
@@ -104,6 +104,8 @@
         else:
             name = 'unnamed' % id(ssarepr)
         i = 1
+        # escape <lambda> names for windows
+        name = name.replace('<lambda>', '_(lambda)_')
         extra = ''
         while name+extra in self._seen_files:
             i += 1
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
@@ -999,12 +999,9 @@
                 "found %d %r, expected %d" % (found, insn, expected_count))
         return insns
 
-    def check_loops(self, expected=None, everywhere=False, **check):
+    def check_resops(self, expected=None, **check):
         insns = {}
         for loop in self.loops:
-            if not everywhere:
-                if getattr(loop, '_ignore_during_counting', False):
-                    continue
             insns = loop.summary(adding_insns=insns)
         if expected is not None:
             insns.pop('debug_merge_point', None)
@@ -1015,7 +1012,7 @@
             assert found == expected_count, (
                 "found %d %r, expected %d" % (found, insn, expected_count))
         return insns
-
+        
     def check_consistency(self):
         "NOT_RPYTHON"
         for loop in self.loops:
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
@@ -348,6 +348,7 @@
         self.opaque_pointers = {}
         self.replaces_guard = {}
         self._newoperations = []
+        self.seen_results = {}
         self.optimizer = self
         self.optpure = None
         self.optearlyforce = None
@@ -542,6 +543,10 @@
                 op = self.store_final_boxes_in_guard(op)
         elif op.can_raise():
             self.exception_might_have_happened = True
+        if op.result:
+            if op.result in self.seen_results:
+                raise ValueError, "invalid optimization"
+            self.seen_results[op.result] = None
         self._newoperations.append(op)
 
     def replace_op(self, old_op, new_op):
@@ -559,9 +564,12 @@
         descr = op.getdescr()
         assert isinstance(descr, compile.ResumeGuardDescr)
         modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)
-        newboxes = modifier.finish(self.values, self.pendingfields)
-        if len(newboxes) > self.metainterp_sd.options.failargs_limit: # XXX be careful here
-            compile.giveup()
+        try:
+            newboxes = modifier.finish(self.values, self.pendingfields)
+            if len(newboxes) > self.metainterp_sd.options.failargs_limit:
+                raise resume.TagOverflow
+        except resume.TagOverflow:
+            raise compile.giveup()
         descr.store_final_boxes(op, newboxes)
         #
         if op.getopnum() == rop.GUARD_VALUE:
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
@@ -1191,6 +1191,75 @@
         """
         self.optimize_loop(ops, expected, preamble)
 
+    def test_virtual_recursive(self):
+        ops = """
+        [p0]
+        p41 = getfield_gc(p0, descr=nextdescr)
+        i0 = getfield_gc(p41, descr=valuedescr)
+        p1 = new_with_vtable(ConstClass(node_vtable2))
+        p2 = new_with_vtable(ConstClass(node_vtable2))
+        setfield_gc(p2, p1, descr=nextdescr)
+        setfield_gc(p1, p2, descr=nextdescr)
+        i1 = int_add(i0, 1)
+        setfield_gc(p2, i1, descr=valuedescr)
+        jump(p1)
+        """
+        preamble = """
+        [p0]
+        p41 = getfield_gc(p0, descr=nextdescr)
+        i0 = getfield_gc(p41, descr=valuedescr)
+        i3 = int_add(i0, 1)
+        jump(i3)
+        """
+        expected = """
+        [i0]
+        i1 = int_add(i0, 1)
+        jump(i1)
+        """
+        self.optimize_loop(ops, expected, preamble)
+
+    def test_virtual_recursive_forced(self):
+        ops = """
+        [p0]
+        p41 = getfield_gc(p0, descr=nextdescr)
+        i0 = getfield_gc(p41, descr=valuedescr)
+        p1 = new_with_vtable(ConstClass(node_vtable2))
+        p2 = new_with_vtable(ConstClass(node_vtable2))
+        setfield_gc(p2, p1, descr=nextdescr)
+        setfield_gc(p1, p2, descr=nextdescr)
+        i1 = int_add(i0, 1)
+        setfield_gc(p2, i1, descr=valuedescr)
+        setfield_gc(p0, p1, descr=nextdescr)
+        jump(p1)
+        """
+        preamble = """
+        [p0]
+        p41 = getfield_gc(p0, descr=nextdescr)
+        i0 = getfield_gc(p41, descr=valuedescr)
+        i1 = int_add(i0, 1)
+        p1 = new_with_vtable(ConstClass(node_vtable2))
+        p2 = new_with_vtable(ConstClass(node_vtable2))
+        setfield_gc(p2, i1, descr=valuedescr)
+        setfield_gc(p2, p1, descr=nextdescr)
+        setfield_gc(p1, p2, descr=nextdescr)
+        setfield_gc(p0, p1, descr=nextdescr)
+        jump(p1)
+        """
+        loop = """
+        [p0]
+        p41 = getfield_gc(p0, descr=nextdescr)
+        i0 = getfield_gc(p41, descr=valuedescr)
+        i1 = int_add(i0, 1)
+        p1 = new_with_vtable(ConstClass(node_vtable2))
+        p2 = new_with_vtable(ConstClass(node_vtable2))
+        setfield_gc(p0, p1, descr=nextdescr)
+        setfield_gc(p2, p1, descr=nextdescr)
+        setfield_gc(p1, p2, descr=nextdescr)
+        setfield_gc(p2, i1, descr=valuedescr)
+        jump(p1)
+        """
+        self.optimize_loop(ops, loop, preamble)
+
     def test_virtual_constant_isnull(self):
         ops = """
         [i0]
@@ -5438,6 +5507,96 @@
         jump()
         """
         self.optimize_loop(ops, expected)
+        # ----------
+        ops = """
+        [p1]
+        p0 = new_with_vtable(ConstClass(ptrobj_immut_vtable))
+        setfield_gc(p0, p1, descr=immut_ptrval)
+        escape(p0)
+        jump(p1)
+        """
+        self.optimize_loop(ops, ops)
+        # ----------
+        ops = """
+        []
+        p0 = new_with_vtable(ConstClass(ptrobj_immut_vtable))
+        p1 = new_with_vtable(ConstClass(intobj_immut_vtable))
+        setfield_gc(p1, 1242, descr=immut_intval)
+        setfield_gc(p0, p1, descr=immut_ptrval)
+        escape(p0)
+        jump()
+        """
+        class PtrObj1242(object):
+            _TYPE = llmemory.GCREF.TO
+            def __eq__(slf, other):
+                if slf is other:
+                    return 1
+                p1 = other.container.ptrval
+                p1cast = lltype.cast_pointer(lltype.Ptr(self.INTOBJ_IMMUT), p1)
+                return p1cast.intval == 1242
+        self.namespace['ptrobj1242'] = lltype._ptr(llmemory.GCREF,
+                                                   PtrObj1242())
+        expected = """
+        []
+        escape(ConstPtr(ptrobj1242))
+        jump()
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_immutable_constantfold_recursive(self):
+        ops = """
+        []
+        p0 = new_with_vtable(ConstClass(ptrobj_immut_vtable))
+        setfield_gc(p0, p0, descr=immut_ptrval)
+        escape(p0)
+        jump()
+        """
+        from pypy.rpython.lltypesystem import lltype, llmemory
+        class PtrObjSelf(object):
+            _TYPE = llmemory.GCREF.TO
+            def __eq__(slf, other):
+                if slf is other:
+                    return 1
+                p1 = other.container.ptrval
+                p1cast = lltype.cast_pointer(lltype.Ptr(self.PTROBJ_IMMUT), p1)
+                return p1cast.ptrval == p1
+        self.namespace['ptrobjself'] = lltype._ptr(llmemory.GCREF,
+                                                   PtrObjSelf())
+        expected = """
+        []
+        escape(ConstPtr(ptrobjself))
+        jump()
+        """
+        self.optimize_loop(ops, expected)
+        #
+        ops = """
+        []
+        p0 = new_with_vtable(ConstClass(ptrobj_immut_vtable))
+        p1 = new_with_vtable(ConstClass(ptrobj_immut_vtable))
+        setfield_gc(p0, p1, descr=immut_ptrval)
+        setfield_gc(p1, p0, descr=immut_ptrval)
+        escape(p0)
+        jump()
+        """
+        class PtrObjSelf2(object):
+            _TYPE = llmemory.GCREF.TO
+            def __eq__(slf, other):
+                if slf is other:
+                    return 1
+                p1 = other.container.ptrval
+                p1cast = lltype.cast_pointer(lltype.Ptr(self.PTROBJ_IMMUT), p1)
+                p2 = p1cast.ptrval
+                assert p2 != p1
+                p2cast = lltype.cast_pointer(lltype.Ptr(self.PTROBJ_IMMUT), p2)
+                return p2cast.ptrval == p1
+        self.namespace['ptrobjself2'] = lltype._ptr(llmemory.GCREF,
+                                                    PtrObjSelf2())
+        expected = """
+        []
+        escape(ConstPtr(ptrobjself2))
+        jump()
+        """
+        self.optimize_loop(ops, expected)
 
     # ----------
     def optimize_strunicode_loop(self, ops, optops, preamble):
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
@@ -139,6 +139,12 @@
     noimmut_intval = cpu.fielddescrof(INTOBJ_NOIMMUT, 'intval')
     immut_intval = cpu.fielddescrof(INTOBJ_IMMUT, 'intval')
 
+    PTROBJ_IMMUT = lltype.GcStruct('PTROBJ_IMMUT', ('parent', OBJECT),
+                                            ('ptrval', lltype.Ptr(OBJECT)),
+                                            hints={'immutable': True})
+    ptrobj_immut_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+    immut_ptrval = cpu.fielddescrof(PTROBJ_IMMUT, 'ptrval')
+
     arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Signed))
     floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float))
 
@@ -246,6 +252,7 @@
     register_known_gctype(cpu, jit_virtual_ref_vtable,vrefinfo.JIT_VIRTUAL_REF)
     register_known_gctype(cpu, intobj_noimmut_vtable, INTOBJ_NOIMMUT)
     register_known_gctype(cpu, intobj_immut_vtable,   INTOBJ_IMMUT)
+    register_known_gctype(cpu, ptrobj_immut_vtable,   PTROBJ_IMMUT)
 
     namespace = locals()
 
diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py
--- a/pypy/jit/metainterp/optimizeopt/virtualize.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualize.py
@@ -87,14 +87,36 @@
     def _get_descr(self):
         raise NotImplementedError
 
-    def _is_immutable_and_filled_with_constants(self, optforce):
+    def _is_immutable_and_filled_with_constants(self, memo=None):
+        # check if it is possible to force the given structure into a
+        # compile-time constant: this is allowed only if it is declared
+        # immutable, if all fields are already filled, and if each field
+        # is either a compile-time constant or (recursively) a structure
+        # which also answers True to the same question.
+        #
+        # check that all fields are filled.  The following equality check
+        # also fails if count == -1, meaning "not an immutable at all".
         count = self._get_descr().count_fields_if_immutable()
-        if count != len(self._fields):    # always the case if count == -1
+        if count != len(self._fields):
             return False
+        #
+        # initialize 'memo'
+        if memo is None:
+            memo = {}
+        elif self in memo:
+            return True   # recursive case: assume yes
+        memo[self] = None
+        #
         for value in self._fields.itervalues():
-            subbox = value.force_box(optforce)
-            if not isinstance(subbox, Const):
-                return False
+            if value.is_constant():
+                pass            # it is a constant value: ok
+            elif (isinstance(value, AbstractVirtualStructValue)
+                  and value.is_virtual()):
+                # recursive check
+                if not value._is_immutable_and_filled_with_constants(memo):
+                    return False
+            else:
+                return False    # not a constant at all
         return True
 
     def force_at_end_of_preamble(self, already_forced, optforce):
@@ -114,7 +136,7 @@
         if not we_are_translated():
             op.name = 'FORCE ' + self.source_op.name
 
-        if self._is_immutable_and_filled_with_constants(optforce):
+        if self._is_immutable_and_filled_with_constants():
             box = optforce.optimizer.constant_fold(op)
             self.make_constant(box)
             for ofs, value in self._fields.iteritems():
diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py
--- a/pypy/jit/metainterp/resume.py
+++ b/pypy/jit/metainterp/resume.py
@@ -93,12 +93,14 @@
 
 TAGMASK = 3
 
+class TagOverflow(Exception):
+    pass
+
 def tag(value, tagbits):
-    if tagbits >> 2:
-        raise ValueError
+    assert 0 <= tagbits <= 3
     sx = value >> 13
     if sx != 0 and sx != -1:
-        raise ValueError
+        raise TagOverflow
     return rffi.r_short(value<<2|tagbits)
 
 def untag(value):
@@ -153,7 +155,7 @@
                 return self._newconst(const)
             try:
                 return tag(val, TAGINT)
-            except ValueError:
+            except TagOverflow:
                 pass
             tagged = self.large_ints.get(val, UNASSIGNED)
             if not tagged_eq(tagged, UNASSIGNED):
@@ -429,8 +431,7 @@
                 fieldnum = self._gettagged(fieldbox)
                 # the index is limited to 2147483647 (64-bit machines only)
                 if itemindex > 2147483647:
-                    from pypy.jit.metainterp import compile
-                    compile.giveup()
+                    raise TagOverflow
                 itemindex = rffi.cast(rffi.INT, itemindex)
                 #
                 rd_pendingfields[i].lldescr  = lldescr
diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py
--- a/pypy/jit/metainterp/test/support.py
+++ b/pypy/jit/metainterp/test/support.py
@@ -155,9 +155,9 @@
 
 class JitMixin:
     basic = True
-    def check_loops(self, expected=None, everywhere=False, **check):
-        get_stats().check_loops(expected=expected, everywhere=everywhere,
-                                **check)
+    def check_resops(self, expected=None, **check):
+        get_stats().check_resops(expected=expected, **check)
+
     def check_loop_count(self, count):
         """NB. This is a hack; use check_tree_loop_count() or
         check_enter_count() for the real thing.
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
@@ -14,7 +14,7 @@
 from pypy.rlib.jit import (JitDriver, we_are_jitted, hint, dont_look_inside,
     loop_invariant, elidable, promote, jit_debug, assert_green,
     AssertGreenFailed, unroll_safe, current_trace_length, look_inside_iff,
-    isconstant, isvirtual, promote_string)
+    isconstant, isvirtual, promote_string, set_param)
 from pypy.rlib.rarithmetic import ovfcheck
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rpython.ootypesystem import ootype
@@ -79,9 +79,8 @@
         res = self.meta_interp(f, [6, 7])
         assert res == 42
         self.check_loop_count(1)
-        self.check_loops({'guard_true': 1,
-                          'int_add': 1, 'int_sub': 1, 'int_gt': 1,
-                          'jump': 1})
+        self.check_resops({'jump': 2, 'int_gt': 2, 'int_add': 2, 'guard_true': 2, 'int_sub': 2})
+
         if self.basic:
             found = 0
             for op in get_stats().loops[0]._all_operations():
@@ -108,7 +107,7 @@
         res = self.meta_interp(f, [6, 7])
         assert res == 1323
         self.check_loop_count(1)
-        self.check_loops(int_mul=1)
+        self.check_resops(int_mul=3)
 
     def test_loop_variant_mul_ovf(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -125,7 +124,7 @@
         res = self.meta_interp(f, [6, 7])
         assert res == 1323
         self.check_loop_count(1)
-        self.check_loops(int_mul_ovf=1)
+        self.check_resops(int_mul_ovf=3)
 
     def test_loop_invariant_mul1(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -140,9 +139,9 @@
         res = self.meta_interp(f, [6, 7])
         assert res == 252
         self.check_loop_count(1)
-        self.check_loops({'guard_true': 1,
-                          'int_add': 1, 'int_sub': 1, 'int_gt': 1,
-                          'jump': 1})
+        self.check_resops({'jump': 2, 'int_gt': 2, 'int_add': 2,
+                           'int_mul': 1, 'guard_true': 2, 'int_sub': 2})
+
 
     def test_loop_invariant_mul_ovf(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -158,10 +157,10 @@
         res = self.meta_interp(f, [6, 7])
         assert res == 308
         self.check_loop_count(1)
-        self.check_loops({'guard_true': 1,
-                          'int_add': 2, 'int_sub': 1, 'int_gt': 1,
-                          'int_lshift': 1,
-                          'jump': 1})
+        self.check_resops({'jump': 2, 'int_lshift': 2, 'int_gt': 2,
+                           'int_mul_ovf': 1, 'int_add': 4,
+                           'guard_true': 2, 'guard_no_overflow': 1,
+                           'int_sub': 2})
 
     def test_loop_invariant_mul_bridge1(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -194,11 +193,9 @@
         res = self.meta_interp(f, [6, 32])
         assert res == 1167
         self.check_loop_count(3)
-        self.check_loops({'int_add': 3, 'int_lt': 2,
-                          'int_sub': 2, 'guard_false': 1,
-                          'jump': 2,
-                          'int_gt': 1, 'guard_true': 2})
-
+        self.check_resops({'int_lt': 3, 'int_gt': 2, 'int_add': 5,
+                           'guard_true': 3, 'int_sub': 4, 'jump': 4,
+                           'int_mul': 2, 'guard_false': 2})
 
     def test_loop_invariant_mul_bridge_maintaining2(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -216,10 +213,9 @@
         res = self.meta_interp(f, [6, 32])
         assert res == 1692
         self.check_loop_count(3)
-        self.check_loops({'int_add': 3, 'int_lt': 2,
-                          'int_sub': 2, 'guard_false': 1,
-                          'jump': 2,
-                          'int_gt': 1, 'guard_true': 2})
+        self.check_resops({'int_lt': 3, 'int_gt': 2, 'int_add': 5,
+                           'guard_true': 3, 'int_sub': 4, 'jump': 4,
+                           'int_mul': 2, 'guard_false': 2})
 
     def test_loop_invariant_mul_bridge_maintaining3(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x', 'm'])
@@ -237,10 +233,9 @@
         res = self.meta_interp(f, [6, 32, 16])
         assert res == 1692
         self.check_loop_count(3)
-        self.check_loops({'int_add': 2, 'int_lt': 1,
-                          'int_sub': 2, 'guard_false': 1,
-                          'jump': 2, 'int_mul': 1,
-                          'int_gt': 2, 'guard_true': 2})
+        self.check_resops({'int_lt': 2, 'int_gt': 4, 'guard_false': 2,
+                           'guard_true': 4, 'int_sub': 4, 'jump': 4,
+                           'int_mul': 3, 'int_add': 4})
 
     def test_loop_invariant_intbox(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -261,9 +256,9 @@
         res = self.meta_interp(f, [6, 7])
         assert res == 252
         self.check_loop_count(1)
-        self.check_loops({'guard_true': 1,
-                          'int_add': 1, 'int_sub': 1, 'int_gt': 1,
-                          'jump': 1})
+        self.check_resops({'jump': 2, 'int_gt': 2, 'int_add': 2,
+                           'getfield_gc_pure': 1, 'int_mul': 1,
+                           'guard_true': 2, 'int_sub': 2})
 
     def test_loops_are_transient(self):
         import gc, weakref
@@ -381,7 +376,7 @@
         assert res == 0
         # CALL_PURE is recorded in the history, but turned into a CALL
         # by optimizeopt.py
-        self.check_loops(int_sub=0, call=1, call_pure=0)
+        self.check_resops(call_pure=0, call=2, int_sub=0)
 
     def test_constfold_call_elidable(self):
         myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
@@ -397,7 +392,7 @@
         res = self.meta_interp(f, [21, 5])
         assert res == -1
         # the CALL_PURE is constant-folded away by optimizeopt.py
-        self.check_loops(int_sub=1, call=0, call_pure=0)
+        self.check_resops(call_pure=0, call=0, int_sub=2)
 
     def test_constfold_call_elidable_2(self):
         myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
@@ -417,7 +412,7 @@
         res = self.meta_interp(f, [21, 5])
         assert res == -1
         # the CALL_PURE is constant-folded away by optimizeopt.py
-        self.check_loops(int_sub=1, call=0, call_pure=0)
+        self.check_resops(call_pure=0, call=0, int_sub=2)
 
     def test_elidable_function_returning_object(self):
         myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
@@ -442,7 +437,7 @@
         res = self.meta_interp(f, [21, 5])
         assert res == -1
         # the CALL_PURE is constant-folded away by optimizeopt.py
-        self.check_loops(int_sub=1, call=0, call_pure=0, getfield_gc=0)
+        self.check_resops(call_pure=0, call=0, getfield_gc=1, int_sub=2)
 
     def test_elidable_raising(self):
         myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
@@ -463,12 +458,12 @@
         res = self.meta_interp(f, [22, 6])
         assert res == -3
         # the CALL_PURE is constant-folded away during tracing
-        self.check_loops(int_sub=1, call=0, call_pure=0)
+        self.check_resops(call_pure=0, call=0, int_sub=2)
         #
         res = self.meta_interp(f, [22, -5])
         assert res == 0
         # raises: becomes CALL and is not constant-folded away
-        self.check_loops(int_sub=1, call=1, call_pure=0)
+        self.check_resops(call_pure=0, call=2, int_sub=2)
 
     def test_elidable_raising_2(self):
         myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
@@ -489,12 +484,12 @@
         res = self.meta_interp(f, [22, 6])
         assert res == -3
         # the CALL_PURE is constant-folded away by optimizeopt.py
-        self.check_loops(int_sub=1, call=0, call_pure=0)
+        self.check_resops(call_pure=0, call=0, int_sub=2)
         #
         res = self.meta_interp(f, [22, -5])
         assert res == 0
         # raises: becomes CALL and is not constant-folded away
-        self.check_loops(int_sub=1, call=1, call_pure=0)
+        self.check_resops(call_pure=0, call=2, int_sub=2)
 
     def test_constant_across_mp(self):
         myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -533,7 +528,7 @@
         policy = StopAtXPolicy(externfn)
         res = self.meta_interp(f, [31], policy=policy)
         assert res == 42
-        self.check_loops(int_mul=1, int_mod=0)
+        self.check_resops(int_mul=2, int_mod=0)
 
     def test_we_are_jitted(self):
         myjitdriver = JitDriver(greens = [], reds = ['y'])
@@ -835,7 +830,7 @@
             return n
         res = self.meta_interp(f, [20, 1, 2])
         assert res == 0
-        self.check_loops(call=0)
+        self.check_resops(call=0)
 
     def test_abs(self):
         myjitdriver = JitDriver(greens = [], reds = ['i', 't'])
@@ -865,9 +860,8 @@
         res = self.meta_interp(f, [6, 7])
         assert res == 42.0
         self.check_loop_count(1)
-        self.check_loops({'guard_true': 1,
-                          'float_add': 1, 'float_sub': 1, 'float_gt': 1,
-                          'jump': 1})
+        self.check_resops({'jump': 2, 'float_gt': 2, 'float_add': 2,
+                           'float_sub': 2, 'guard_true': 2})
 
     def test_print(self):
         myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -1038,7 +1032,7 @@
             return x
         res = self.meta_interp(f, [20], enable_opts='')
         assert res == f(20)
-        self.check_loops(call=0)
+        self.check_resops(call=0)
 
     def test_zerodivisionerror(self):
         # test the case of exception-raising operation that is not delegated
@@ -1256,15 +1250,18 @@
                 n -= 1
                 x += n
             return x
-        def f(n, threshold):
-            myjitdriver.set_param('threshold', threshold)
+        def f(n, threshold, arg):
+            if arg:
+                set_param(myjitdriver, 'threshold', threshold)
+            else:
+                set_param(None, 'threshold', threshold)
             return g(n)
 
-        res = self.meta_interp(f, [10, 3])
+        res = self.meta_interp(f, [10, 3, 1])
         assert res == 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
         self.check_tree_loop_count(2)
 
-        res = self.meta_interp(f, [10, 13])
+        res = self.meta_interp(f, [10, 13, 0])
         assert res == 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
         self.check_tree_loop_count(0)
 
@@ -1348,7 +1345,7 @@
         res = self.meta_interp(f, [6, 7])
         assert res == 42
         self.check_loop_count(1)
-        self.check_loops(call=1)
+        self.check_resops(call=2)
 
     def test_merge_guardclass_guardvalue(self):
         from pypy.rlib.objectmodel import instantiate
@@ -1375,8 +1372,7 @@
             return x
         res = self.meta_interp(f, [299], listops=True)
         assert res == f(299)
-        self.check_loops(guard_class=0, guard_value=3)
-        self.check_loops(guard_class=0, guard_value=6, everywhere=True)
+        self.check_resops(guard_class=0, guard_value=6)
 
     def test_merge_guardnonnull_guardclass(self):
         from pypy.rlib.objectmodel import instantiate
@@ -1404,11 +1400,9 @@
             return x
         res = self.meta_interp(f, [299], listops=True)
         assert res == f(299)
-        self.check_loops(guard_class=0, guard_nonnull=2,
-                         guard_nonnull_class=2, guard_isnull=1)
-        self.check_loops(guard_class=0, guard_nonnull=4,
-                         guard_nonnull_class=4, guard_isnull=2,
-                         everywhere=True)
+        self.check_resops(guard_class=0, guard_nonnull=4,
+                          guard_nonnull_class=4, guard_isnull=2)
+        
 
     def test_merge_guardnonnull_guardvalue(self):
         from pypy.rlib.objectmodel import instantiate
@@ -1435,11 +1429,9 @@
             return x
         res = self.meta_interp(f, [299], listops=True)
         assert res == f(299)
-        self.check_loops(guard_class=0, guard_nonnull=2, guard_value=2,
-                         guard_nonnull_class=0, guard_isnull=1)
-        self.check_loops(guard_class=0, guard_nonnull=4, guard_value=4,
-                         guard_nonnull_class=0, guard_isnull=2,
-                         everywhere=True)
+        self.check_resops(guard_value=4, guard_class=0, guard_nonnull=4,
+                          guard_nonnull_class=0, guard_isnull=2)
+        
 
     def test_merge_guardnonnull_guardvalue_2(self):
         from pypy.rlib.objectmodel import instantiate
@@ -1466,11 +1458,9 @@
             return x
         res = self.meta_interp(f, [299], listops=True)
         assert res == f(299)
-        self.check_loops(guard_class=0, guard_nonnull=2, guard_value=2,
-                         guard_nonnull_class=0, guard_isnull=1)
-        self.check_loops(guard_class=0, guard_nonnull=4, guard_value=4,
-                         guard_nonnull_class=0, guard_isnull=2,
-                         everywhere=True)
+        self.check_resops(guard_value=4, guard_class=0, guard_nonnull=4,
+                          guard_nonnull_class=0, guard_isnull=2)
+        
 
     def test_merge_guardnonnull_guardclass_guardvalue(self):
         from pypy.rlib.objectmodel import instantiate
@@ -1500,11 +1490,9 @@
             return x
         res = self.meta_interp(f, [399], listops=True)
         assert res == f(399)
-        self.check_loops(guard_class=0, guard_nonnull=3, guard_value=3,
-                         guard_nonnull_class=0, guard_isnull=1)
-        self.check_loops(guard_class=0, guard_nonnull=6, guard_value=6,
-                         guard_nonnull_class=0, guard_isnull=2,
-                         everywhere=True)
+        self.check_resops(guard_class=0, guard_nonnull=6, guard_value=6,
+                          guard_nonnull_class=0, guard_isnull=2)
+
 
     def test_residual_call_doesnt_lose_info(self):
         myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'l'])
@@ -1530,8 +1518,7 @@
                 y.v = g(y.v) - y.v/y.v + lc/l[0] - 1
             return y.v
         res = self.meta_interp(f, [20], listops=True)
-        self.check_loops(getfield_gc=0, getarrayitem_gc=0)
-        self.check_loops(getfield_gc=1, getarrayitem_gc=0, everywhere=True)
+        self.check_resops(getarrayitem_gc=0, getfield_gc=1)
 
     def test_guard_isnull_nonnull(self):
         myjitdriver = JitDriver(greens = [], reds = ['x', 'res'])
@@ -1559,7 +1546,7 @@
             return res
         res = self.meta_interp(f, [21])
         assert res == 42
-        self.check_loops(guard_nonnull=1, guard_isnull=1)
+        self.check_resops(guard_nonnull=2, guard_isnull=2)
 
     def test_loop_invariant1(self):
         myjitdriver = JitDriver(greens = [], reds = ['x', 'res'])
@@ -1586,8 +1573,7 @@
             return res
         res = self.meta_interp(g, [21])
         assert res == 3 * 21
-        self.check_loops(call=0)
-        self.check_loops(call=1, everywhere=True)
+        self.check_resops(call=1)
 
     def test_bug_optimizeopt_mutates_ops(self):
         myjitdriver = JitDriver(greens = [], reds = ['x', 'res', 'const', 'a'])
@@ -1707,7 +1693,7 @@
             return x
         res = self.meta_interp(f, [8])
         assert res == 0
-        self.check_loops(jit_debug=2)
+        self.check_resops(jit_debug=4)
 
     def test_assert_green(self):
         def f(x, promote_flag):
@@ -1749,9 +1735,10 @@
         res = self.meta_interp(g, [6, 7])
         assert res == 6*8 + 6**8
         self.check_loop_count(5)
-        self.check_loops({'guard_true': 2,
-                          'int_add': 1, 'int_mul': 1, 'int_sub': 2,
-                          'int_gt': 2, 'jump': 2})
+        self.check_resops({'guard_class': 2, 'int_gt': 4,
+                           'getfield_gc': 4, 'guard_true': 4,
+                           'int_sub': 4, 'jump': 4, 'int_mul': 2,
+                           'int_add': 2})
 
     def test_multiple_specialied_versions_array(self):
         myjitdriver = JitDriver(greens = [], reds = ['idx', 'y', 'x', 'res',
@@ -1792,7 +1779,7 @@
         res = self.meta_interp(g, [6, 14])
         assert res == g(6, 14)
         self.check_loop_count(9)
-        self.check_loops(getarrayitem_gc=8, everywhere=True)
+        self.check_resops(getarrayitem_gc=8)
 
     def test_multiple_specialied_versions_bridge(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
@@ -1980,8 +1967,8 @@
         res = self.meta_interp(g, [3, 23])
         assert res == 7068153
         self.check_loop_count(7)
-        self.check_loops(guard_true=4, guard_class=0, int_add=2, int_mul=2,
-                         guard_false=2)
+        self.check_resops(guard_true=6, guard_class=2, int_mul=3,
+                          int_add=3, guard_false=3)
 
     def test_dont_trace_every_iteration(self):
         myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa'])
@@ -2225,27 +2212,27 @@
             return sa
 
         assert self.meta_interp(f1, [5, 5]) == 50
-        self.check_loops(int_rshift=0, everywhere=True)
+        self.check_resops(int_rshift=0)
 
         for f in (f1, f2):
             assert self.meta_interp(f, [5, 6]) == 50
-            self.check_loops(int_rshift=3, everywhere=True)
+            self.check_resops(int_rshift=3)
 
             assert self.meta_interp(f, [10, 5]) == 100
-            self.check_loops(int_rshift=3, everywhere=True)
+            self.check_resops(int_rshift=3)
 
             assert self.meta_interp(f, [10, 6]) == 100
-            self.check_loops(int_rshift=3, everywhere=True)
+            self.check_resops(int_rshift=3)
 
             assert self.meta_interp(f, [5, 31]) == 0
-            self.check_loops(int_rshift=3, everywhere=True)
+            self.check_resops(int_rshift=3)
 
             bigval = 1
             while (bigval << 3).__class__ is int:
                 bigval = bigval << 1
 
             assert self.meta_interp(f, [bigval, 5]) == 0
-            self.check_loops(int_rshift=3, everywhere=True)
+            self.check_resops(int_rshift=3)
 
     def test_overflowing_shift_neg(self):
         myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'n', 'sa'])
@@ -2270,27 +2257,27 @@
             return sa
 
         assert self.meta_interp(f1, [-5, 5]) == -50
-        self.check_loops(int_rshift=0, everywhere=True)
+        self.check_resops(int_rshift=0)
 
         for f in (f1, f2):
             assert self.meta_interp(f, [-5, 6]) == -50
-            self.check_loops(int_rshift=3, everywhere=True)
+            self.check_resops(int_rshift=3)
 
             assert self.meta_interp(f, [-10, 5]) == -100
-            self.check_loops(int_rshift=3, everywhere=True)
+            self.check_resops(int_rshift=3)
 
             assert self.meta_interp(f, [-10, 6]) == -100
-            self.check_loops(int_rshift=3, everywhere=True)
+            self.check_resops(int_rshift=3)
 
             assert self.meta_interp(f, [-5, 31]) == 0
-            self.check_loops(int_rshift=3, everywhere=True)
+            self.check_resops(int_rshift=3)
 
             bigval = 1
             while (bigval << 3).__class__ is int:
                 bigval = bigval << 1
 
             assert self.meta_interp(f, [bigval, 5]) == 0
-            self.check_loops(int_rshift=3, everywhere=True)
+            self.check_resops(int_rshift=3)
 
     def test_pure_op_not_to_be_propagated(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'sa'])
@@ -2328,8 +2315,8 @@
                                 get_printable_location=get_printable_location)
         bytecode = "0j10jc20a3"
         def f():
-            myjitdriver.set_param('threshold', 7)
-            myjitdriver.set_param('trace_eagerness', 1)
+            set_param(myjitdriver, 'threshold', 7)
+            set_param(myjitdriver, 'trace_eagerness', 1)
             i = j = c = a = 1
             while True:
                 myjitdriver.jit_merge_point(i=i, j=j, c=c, a=a)
@@ -2430,8 +2417,7 @@
                 if counter > 10:
                     return 7
         assert self.meta_interp(build, []) == 7
-        self.check_loops(getfield_gc_pure=0)
-        self.check_loops(getfield_gc_pure=2, everywhere=True)
+        self.check_resops(getfield_gc_pure=2)
 
     def test_args_becomming_equal(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a', 'b'])
@@ -2564,7 +2550,7 @@
                 i += 1
             return sa
         assert self.meta_interp(f, [20]) == f(20)
-        self.check_loops(int_gt=1, int_lt=2, int_ge=0, int_le=0)
+        self.check_resops(int_lt=4, int_le=0, int_ge=0, int_gt=2)
 
     def test_intbounds_not_generalized1(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa'])
@@ -2581,7 +2567,8 @@
                 i += 1
             return sa
         assert self.meta_interp(f, [20]) == f(20)
-        self.check_loops(int_gt=1, int_lt=3, int_ge=2, int_le=1)
+        self.check_resops(int_lt=6, int_le=2, int_ge=4, int_gt=3)
+        
 
     def test_intbounds_not_generalized2(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'node'])
@@ -2601,13 +2588,13 @@
                 i += 1
             return sa
         assert self.meta_interp(f, [20]) == f(20)
-        self.check_loops(int_gt=1, int_lt=2, int_ge=1, int_le=1)
+        self.check_resops(int_lt=4, int_le=3, int_ge=3, int_gt=2)
 
     def test_retrace_limit1(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a'])
 
         def f(n, limit):
-            myjitdriver.set_param('retrace_limit', limit)
+            set_param(myjitdriver, 'retrace_limit', limit)
             sa = i = a = 0
             while i < n:
                 myjitdriver.jit_merge_point(n=n, i=i, sa=sa, a=a)
@@ -2625,8 +2612,8 @@
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a'])
 
         def f(n, limit):
-            myjitdriver.set_param('retrace_limit', 3)
-            myjitdriver.set_param('max_retrace_guards', limit)
+            set_param(myjitdriver, 'retrace_limit', 3)
+            set_param(myjitdriver, 'max_retrace_guards', limit)
             sa = i = a = 0
             while i < n:
                 myjitdriver.jit_merge_point(n=n, i=i, sa=sa, a=a)
@@ -2645,7 +2632,7 @@
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a',
                                                      'node'])
         def f(n, limit):
-            myjitdriver.set_param('retrace_limit', limit)
+            set_param(myjitdriver, 'retrace_limit', limit)
             sa = i = a = 0
             node = [1, 2, 3]
             node[1] = n
@@ -2668,10 +2655,10 @@
         myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa'])
         bytecode = "0+sI0+SI"
         def f(n):
-            myjitdriver.set_param('threshold', 3)
-            myjitdriver.set_param('trace_eagerness', 1)
-            myjitdriver.set_param('retrace_limit', 5)
-            myjitdriver.set_param('function_threshold', -1)
+            set_param(None, 'threshold', 3)
+            set_param(None, 'trace_eagerness', 1)
+            set_param(None, 'retrace_limit', 5)
+            set_param(None, 'function_threshold', -1)
             pc = sa = i = 0
             while pc < len(bytecode):
                 myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i)
@@ -2728,9 +2715,9 @@
         myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'a', 'i', 'j', 'sa'])
         bytecode = "ij+Jj+JI"
         def f(n, a):
-            myjitdriver.set_param('threshold', 5)
-            myjitdriver.set_param('trace_eagerness', 1)
-            myjitdriver.set_param('retrace_limit', 2)
+            set_param(None, 'threshold', 5)
+            set_param(None, 'trace_eagerness', 1)
+            set_param(None, 'retrace_limit', 2)
             pc = sa = i = j = 0
             while pc < len(bytecode):
                 myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i, j=j, a=a)
@@ -2793,8 +2780,8 @@
                 return B(self.val + 1)
         myjitdriver = JitDriver(greens = [], reds = ['sa', 'a'])
         def f():
-            myjitdriver.set_param('threshold', 3)
-            myjitdriver.set_param('trace_eagerness', 2)
+            set_param(None, 'threshold', 3)
+            set_param(None, 'trace_eagerness', 2)
             a = A(0)
             sa = 0
             while a.val < 8:
@@ -2824,8 +2811,8 @@
                 return B(self.val + 1)
         myjitdriver = JitDriver(greens = [], reds = ['sa', 'b', 'a'])
         def f(b):
-            myjitdriver.set_param('threshold', 6)
-            myjitdriver.set_param('trace_eagerness', 4)
+            set_param(None, 'threshold', 6)
+            set_param(None, 'trace_eagerness', 4)
             a = A(0)
             sa = 0
             while a.val < 15:
@@ -2855,17 +2842,17 @@
             return a[0].intvalue
         res = self.meta_interp(f, [100])
         assert res == -2
-        #self.check_loops(getarrayitem_gc=0, setarrayitem_gc=0) -- xxx?
+        self.check_resops(setarrayitem_gc=2, getarrayitem_gc=1)
 
     def test_retrace_ending_up_retracing_another_loop(self):
 
         myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'i', 'sa'])
         bytecode = "0+sI0+SI"
         def f(n):
-            myjitdriver.set_param('threshold', 3)
-            myjitdriver.set_param('trace_eagerness', 1)
-            myjitdriver.set_param('retrace_limit', 5)
-            myjitdriver.set_param('function_threshold', -1)
+            set_param(None, 'threshold', 3)
+            set_param(None, 'trace_eagerness', 1)
+            set_param(None, 'retrace_limit', 5)
+            set_param(None, 'function_threshold', -1)
             pc = sa = i = 0
             while pc < len(bytecode):
                 myjitdriver.jit_merge_point(pc=pc, n=n, sa=sa, i=i)
@@ -2955,7 +2942,7 @@
                 i += 1
         res = self.meta_interp(f, [32])
         assert res == f(32)
-        self.check_loops(arraylen_gc=2)
+        self.check_resops(arraylen_gc=3)
 
     def test_ulonglong_mod(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'sa', 'i'])
@@ -3142,9 +3129,9 @@
                 a = A(a.i + 1)
 
         self.meta_interp(f, [])
-        self.check_loops(new_with_vtable=0)
+        self.check_resops(new_with_vtable=0)
         self.meta_interp(f, [], enable_opts='')
-        self.check_loops(new_with_vtable=1)
+        self.check_resops(new_with_vtable=1)
 
     def test_two_loopinvariant_arrays1(self):
         from pypy.rpython.lltypesystem import lltype, llmemory, rffi
@@ -3236,7 +3223,7 @@
             return sa
         res = self.meta_interp(f, [32])
         assert res == f(32)
-        self.check_loops(arraylen_gc=2, everywhere=True)
+        self.check_resops(arraylen_gc=2)
 
     def test_release_gil_flush_heap_cache(self):
         if sys.platform == "win32":
@@ -3273,7 +3260,7 @@
                 lock.release()
             return n
         res = self.meta_interp(f, [10, 1])
-        self.check_loops(getfield_gc=2)
+        self.check_resops(getfield_gc=4)
         assert res == f(10, 1)
 
     def test_jit_merge_point_with_raw_pointer(self):
@@ -3337,10 +3324,10 @@
 
         res = self.meta_interp(main, [0, 10, 2], enable_opts='')
         assert res == main(0, 10, 2)
-        self.check_loops(call=1)
+        self.check_resops(call=1)
         res = self.meta_interp(main, [1, 10, 2], enable_opts='')
         assert res == main(1, 10, 2)
-        self.check_loops(call=0)
+        self.check_resops(call=0)
 
     def test_look_inside_iff_virtual(self):
         # There's no good reason for this to be look_inside_iff, but it's a test!
@@ -3365,10 +3352,10 @@
                     i += f(A(2), n)
         res = self.meta_interp(main, [0], enable_opts='')
         assert res == main(0)
-        self.check_loops(call=1, getfield_gc=0)
+        self.check_resops(call=1, getfield_gc=0)
         res = self.meta_interp(main, [1], enable_opts='')
         assert res == main(1)
-        self.check_loops(call=0, getfield_gc=0)
+        self.check_resops(call=0, getfield_gc=0)
 
     def test_reuse_elidable_result(self):
         driver = JitDriver(reds=['n', 's'], greens = [])
@@ -3381,10 +3368,9 @@
             return s
         res = self.meta_interp(main, [10])
         assert res == main(10)
-        self.check_loops({
-            'call': 1, 'guard_no_exception': 1, 'guard_true': 1, 'int_add': 2,
-            'int_gt': 1, 'int_sub': 1, 'strlen': 1, 'jump': 1,
-        })
+        self.check_resops({'int_gt': 2, 'strlen': 2, 'guard_true': 2,
+                           'int_sub': 2, 'jump': 2, 'call': 2,
+                           'guard_no_exception': 2, 'int_add': 4})
 
     def test_look_inside_iff_const_getarrayitem_gc_pure(self):
         driver = JitDriver(greens=['unroll'], reds=['s', 'n'])
@@ -3416,10 +3402,10 @@
         res = self.meta_interp(main, [0, 10])
         assert res == main(0, 10)
         # 2 calls, one for f() and one for char_mul
-        self.check_loops(call=2)
+        self.check_resops(call=4)
         res = self.meta_interp(main, [1, 10])
         assert res == main(1, 10)
-        self.check_loops(call=0)
+        self.check_resops(call=0)
 
     def test_setarrayitem_followed_by_arraycopy(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'sa', 'x', 'y'])
@@ -3520,7 +3506,8 @@
 
         res = self.meta_interp(f, [10])
         assert res == 0
-        self.check_loops({"int_sub": 1, "int_gt": 1, "guard_true": 1, "jump": 1})
+        self.check_resops({'jump': 2, 'guard_true': 2, 'int_gt': 2,
+                           'int_sub': 2})
 
     def test_virtual_opaque_ptr(self):
         myjitdriver = JitDriver(greens = [], reds = ["n"])
@@ -3539,7 +3526,9 @@
             return n
         res = self.meta_interp(f, [10])
         assert res == 0
-        self.check_loops({"int_sub": 1, "int_gt": 1, "guard_true": 1, "jump": 1})
+        self.check_resops({'jump': 2, 'guard_true': 2, 'int_gt': 2,
+                           'int_sub': 2})
+
 
     def test_virtual_opaque_dict(self):
         myjitdriver = JitDriver(greens = [], reds = ["n"])
@@ -3559,7 +3548,10 @@
             return n
         res = self.meta_interp(f, [10])
         assert res == 0
-        self.check_loops({"int_sub": 1, "int_gt": 1, "guard_true": 1, "jump": 1})
+        self.check_resops({'int_gt': 2, 'getfield_gc': 1, 'int_eq': 1,
+                           'guard_true': 2, 'int_sub': 2, 'jump': 2,
+                           'guard_false': 1})
+
 
     def test_convert_from_SmallFunctionSetPBCRepr_to_FunctionsPBCRepr(self):
         f1 = lambda n: n+1
diff --git a/pypy/jit/metainterp/test/test_del.py b/pypy/jit/metainterp/test/test_del.py
--- a/pypy/jit/metainterp/test/test_del.py
+++ b/pypy/jit/metainterp/test/test_del.py
@@ -20,12 +20,12 @@
                 n -= 1
             return 42
         self.meta_interp(f, [20])
-        self.check_loops({'call': 2,      # calls to a helper function
-                          'guard_no_exception': 2,    # follows the calls
-                          'int_sub': 1,
-                          'int_gt': 1,
-                          'guard_true': 1,
-                          'jump': 1})
+        self.check_resops({'call': 4,      # calls to a helper function
+                           'guard_no_exception': 4,    # follows the calls
+                           'int_sub': 2,
+                           'int_gt': 2,
+                           'guard_true': 2,
+                           'jump': 2})
 
     def test_class_of_allocated(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
@@ -78,7 +78,7 @@
             return 1
         res = self.meta_interp(f, [20], enable_opts='')
         assert res == 1
-        self.check_loops(call=1)   # for the case B(), but not for the case A()
+        self.check_resops(call=1)   # for the case B(), but not for the case A()
 
 
 class TestLLtype(DelTests, LLJitMixin):
@@ -103,7 +103,7 @@
                     break
             return 42
         self.meta_interp(f, [20])
-        self.check_loops(getfield_raw=1, setfield_raw=1, call=0, call_pure=0)
+        self.check_resops(call_pure=0, setfield_raw=2, call=0, getfield_raw=2)
 
 class TestOOtype(DelTests, OOJitMixin):
     def setup_class(cls):
diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py
--- a/pypy/jit/metainterp/test/test_dict.py
+++ b/pypy/jit/metainterp/test/test_dict.py
@@ -91,7 +91,7 @@
         res1 = f(100)
         res2 = self.meta_interp(f, [100], listops=True)
         assert res1 == res2
-        self.check_loops(int_mod=1) # the hash was traced and eq, but cached
+        self.check_resops(int_mod=2) # the hash was traced and eq, but cached
 
     def test_dict_setdefault(self):
         myjitdriver = JitDriver(greens = [], reds = ['total', 'dct'])
@@ -107,7 +107,7 @@
         assert f(100) == 50
         res = self.meta_interp(f, [100], listops=True)
         assert res == 50
-        self.check_loops(new=0, new_with_vtable=0)
+        self.check_resops(new=0, new_with_vtable=0)
 
     def test_dict_as_counter(self):
         myjitdriver = JitDriver(greens = [], reds = ['total', 'dct'])
@@ -128,7 +128,7 @@
         assert f(100) == 50
         res = self.meta_interp(f, [100], listops=True)
         assert res == 50
-        self.check_loops(int_mod=1) # key + eq, but cached
+        self.check_resops(int_mod=2) # key + eq, but cached
 
     def test_repeated_lookup(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'd'])
@@ -153,12 +153,13 @@
 
         res = self.meta_interp(f, [100], listops=True)
         assert res == f(50)
-        self.check_loops({"call": 5, "getfield_gc": 1, "getinteriorfield_gc": 1,
-                          "guard_false": 1, "guard_no_exception": 4,
-                          "guard_true": 1, "int_and": 1, "int_gt": 1,
-                          "int_is_true": 1, "int_sub": 1, "jump": 1,
-                          "new_with_vtable": 1, "new": 1, "new_array": 1,
-                          "setfield_gc": 3, })
+        self.check_resops({'new_array': 2, 'getfield_gc': 2,
+                           'guard_true': 2, 'jump': 2,
+                           'new_with_vtable': 2, 'getinteriorfield_gc': 2,
+                           'setfield_gc': 6, 'int_gt': 2, 'int_sub': 2,
+                           'call': 10, 'int_and': 2,
+                           'guard_no_exception': 8, 'new': 2,
+                           'guard_false': 2, 'int_is_true': 2})
 
 
 class TestOOtype(DictTests, OOJitMixin):
diff --git a/pypy/jit/metainterp/test/test_exception.py b/pypy/jit/metainterp/test/test_exception.py
--- a/pypy/jit/metainterp/test/test_exception.py
+++ b/pypy/jit/metainterp/test/test_exception.py
@@ -35,10 +35,8 @@
             return n
         res = self.meta_interp(f, [10])
         assert res == 0
-        self.check_loops({'jump': 1,
-                          'int_gt': 1, 'guard_true': 1,
-                          'int_sub': 1})
-
+        self.check_resops({'jump': 2, 'guard_true': 2,
+                           'int_gt': 2, 'int_sub': 2})
 
     def test_bridge_from_guard_exception(self):
         myjitdriver = JitDriver(greens = [], reds = ['n'])
diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py
--- a/pypy/jit/metainterp/test/test_fficall.py
+++ b/pypy/jit/metainterp/test/test_fficall.py
@@ -67,23 +67,23 @@
              'byval': False}
         supported = all(d[check] for check in jitif)
         if supported:
-            self.check_loops(
-                call_release_gil=1,   # a CALL_RELEASE_GIL, and no other CALLs
+            self.check_resops(
+                call_release_gil=2,   # a CALL_RELEASE_GIL, and no other CALLs
                 call=0,
                 call_may_force=0,
-                guard_no_exception=1,
-                guard_not_forced=1,
-                int_add=1,
-                int_lt=1,
-                guard_true=1,
-                jump=1)
+                guard_no_exception=2,
+                guard_not_forced=2,
+                int_add=2,
+                int_lt=2,
+                guard_true=2,
+                jump=2)
         else:
-            self.check_loops(
+            self.check_resops(
                 call_release_gil=0,   # no CALL_RELEASE_GIL
-                int_add=1,
-                int_lt=1,
-                guard_true=1,
-                jump=1)
+                int_add=2,
+                int_lt=2,
+                guard_true=2,
+                jump=2)
         return res
 
     def test_byval_result(self):
@@ -144,10 +144,8 @@
                     return result_point[0].x * result_point[0].y
 
         assert self.meta_interp(main, [10]) == main(10) == 9000
-        self.check_loops({"int_add": 3, "jump": 1, "int_lt": 1, "guard_true": 1,
-                          "getinteriorfield_raw": 4, "setinteriorfield_raw": 2
-        })
-
+        self.check_resops({'jump': 2, 'int_lt': 2, 'setinteriorfield_raw': 4,
+                           'getinteriorfield_raw': 8, 'int_add': 6, 'guard_true': 2})
 
 class TestFfiCall(FfiCallTests, LLJitMixin):
     supports_all = False
@@ -156,4 +154,4 @@
     supports_all = True     # supports_{floats,longlong,singlefloats}
 
 class TestFfiLookup(FfiLookupTests, LLJitMixin):
-    pass
\ No newline at end of file
+    pass
diff --git a/pypy/jit/metainterp/test/test_greenfield.py b/pypy/jit/metainterp/test/test_greenfield.py
--- a/pypy/jit/metainterp/test/test_greenfield.py
+++ b/pypy/jit/metainterp/test/test_greenfield.py
@@ -25,7 +25,7 @@
         res = self.meta_interp(g, [7])
         assert res == -2
         self.check_loop_count(2)
-        self.check_loops(guard_value=0)
+        self.check_resops(guard_value=0)
 
     def test_green_field_2(self):
         myjitdriver = JitDriver(greens=['ctx.x'], reds=['ctx'])
@@ -50,7 +50,7 @@
         res = self.meta_interp(g, [7])
         assert res == -22
         self.check_loop_count(6)
-        self.check_loops(guard_value=0)
+        self.check_resops(guard_value=0)
 
 
 class TestLLtypeGreenFieldsTests(GreenFieldsTests, LLJitMixin):
diff --git a/pypy/jit/metainterp/test/test_jitdriver.py b/pypy/jit/metainterp/test/test_jitdriver.py
--- a/pypy/jit/metainterp/test/test_jitdriver.py
+++ b/pypy/jit/metainterp/test/test_jitdriver.py
@@ -1,5 +1,5 @@
 """Tests for multiple JitDrivers."""
-from pypy.rlib.jit import JitDriver, unroll_safe
+from pypy.rlib.jit import JitDriver, unroll_safe, set_param
 from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
 from pypy.jit.metainterp.warmspot import get_stats
 
@@ -88,7 +88,7 @@
         assert res == loop2(4, 40)
         # we expect only one int_sub, corresponding to the single
         # compiled instance of loop1()
-        self.check_loops(int_sub=1)
+        self.check_resops(int_sub=2)
         # the following numbers are not really expectations of the test
         # itself, but just the numbers that we got after looking carefully
         # at the generated machine code
@@ -113,7 +113,7 @@
             return n
         #
         def loop2(g, r):
-            myjitdriver1.set_param('function_threshold', 0)
+            set_param(None, 'function_threshold', 0)
             while r > 0:
                 myjitdriver2.can_enter_jit(g=g, r=r)
                 myjitdriver2.jit_merge_point(g=g, r=r)
@@ -154,7 +154,7 @@
         res = self.meta_interp(loop2, [4, 40], repeat=7, inline=True)
         assert res == loop2(4, 40)
         # we expect no int_sub, but a residual call
-        self.check_loops(int_sub=0, call=1)
+        self.check_resops(call=2, int_sub=0)
 
     def test_multiple_jits_trace_too_long(self):
         myjitdriver1 = JitDriver(greens=["n"], reds=["i", "box"])
diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py
--- a/pypy/jit/metainterp/test/test_list.py
+++ b/pypy/jit/metainterp/test/test_list.py
@@ -6,8 +6,8 @@
 class ListTests:
 
     def check_all_virtualized(self):
-        self.check_loops(new_array=0, setarrayitem_gc=0, getarrayitem_gc=0,
-                         arraylen_gc=0)
+        self.check_resops(setarrayitem_gc=0, new_array=0, arraylen_gc=0,
+                          getarrayitem_gc=0)
 
     def test_simple_array(self):
         jitdriver = JitDriver(greens = [], reds = ['n'])
@@ -20,7 +20,7 @@
             return n
         res = self.meta_interp(f, [10], listops=True)
         assert res == 0
-        self.check_loops(int_sub=1)
+        self.check_resops(int_sub=2)
         self.check_all_virtualized()
 
     def test_list_pass_around(self):
@@ -56,7 +56,8 @@
         res = self.meta_interp(f, [10], listops=True)
         assert res == f(10)
         # one setitem should be gone by now
-        self.check_loops(call=1, setarrayitem_gc=2, getarrayitem_gc=1)
+        self.check_resops(setarrayitem_gc=4, getarrayitem_gc=2, call=2)
+
 
     def test_ll_fixed_setitem_fast(self):
         jitdriver = JitDriver(greens = [], reds = ['n', 'l'])
@@ -93,7 +94,7 @@
 
         res = self.meta_interp(f, [10], listops=True)
         assert res == f(10)
-        self.check_loops(setarrayitem_gc=0, getarrayitem_gc=0, call=0)
+        self.check_resops(setarrayitem_gc=0, call=0, getarrayitem_gc=0)
 
     def test_vlist_alloc_and_set(self):
         # the check_loops fails, because [non-null] * n is not supported yet
@@ -141,7 +142,7 @@
 
         res = self.meta_interp(f, [5], listops=True)
         assert res == 7
-        self.check_loops(call=0)
+        self.check_resops(call=0)
 
     def test_fold_getitem_1(self):
         jitdriver = JitDriver(greens = ['pc', 'n', 'l'], reds = ['total'])
@@ -161,7 +162,7 @@
 
         res = self.meta_interp(f, [4], listops=True)
         assert res == f(4)
-        self.check_loops(call=0)
+        self.check_resops(call=0)
 
     def test_fold_getitem_2(self):
         jitdriver = JitDriver(greens = ['pc', 'n', 'l'], reds = ['total', 'x'])
@@ -186,7 +187,7 @@
 
         res = self.meta_interp(f, [4], listops=True)
         assert res == f(4)
-        self.check_loops(call=0, getfield_gc=0)
+        self.check_resops(call=0, getfield_gc=0)
 
     def test_fold_indexerror(self):
         jitdriver = JitDriver(greens = [], reds = ['total', 'n', 'lst'])
@@ -206,7 +207,7 @@
 
         res = self.meta_interp(f, [15], listops=True)
         assert res == f(15)
-        self.check_loops(guard_exception=0)
+        self.check_resops(guard_exception=0)
 
     def test_virtual_resize(self):
         jitdriver = JitDriver(greens = [], reds = ['n', 's'])
@@ -224,9 +225,8 @@
             return s
         res = self.meta_interp(f, [15], listops=True)
         assert res == f(15)
-        self.check_loops({"int_add": 1, "int_sub": 1, "int_gt": 1,
-                          "guard_true": 1, "jump": 1})
-
+        self.check_resops({'jump': 2, 'int_gt': 2, 'int_add': 2,
+                           'guard_true': 2, 'int_sub': 2})
 
 class TestOOtype(ListTests, OOJitMixin):
     pass
@@ -258,4 +258,4 @@
         assert res == f(37)
         # There is the one actual field on a, plus several fields on the list
         # itself
-        self.check_loops(getfield_gc=10, everywhere=True)
+        self.check_resops(getfield_gc=10)
diff --git a/pypy/jit/metainterp/test/test_loop.py b/pypy/jit/metainterp/test/test_loop.py
--- a/pypy/jit/metainterp/test/test_loop.py
+++ b/pypy/jit/metainterp/test/test_loop.py
@@ -1,5 +1,5 @@
 import py
-from pypy.rlib.jit import JitDriver, hint
+from pypy.rlib.jit import JitDriver, hint, set_param
 from pypy.rlib.objectmodel import compute_hash
 from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
 from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
@@ -60,7 +60,8 @@
         assert res == f(6, 13)
         self.check_loop_count(1)
         if self.enable_opts:
-            self.check_loops(getfield_gc = 0, setfield_gc = 1)
+            self.check_resops(setfield_gc=2, getfield_gc=0)
+
 
     def test_loop_with_two_paths(self):
         from pypy.rpython.lltypesystem import lltype
@@ -180,7 +181,10 @@
         assert res == 42
         self.check_loop_count(1)
         # the 'int_eq' and following 'guard' should be constant-folded
-        self.check_loops(int_eq=0, guard_true=1, guard_false=0)
+        if 'unroll' in self.enable_opts:
+            self.check_resops(int_eq=0, guard_true=2, guard_false=0)
+        else:
+            self.check_resops(int_eq=0, guard_true=1, guard_false=0)
         if self.basic:
             found = 0
             for op in get_stats().loops[0]._all_operations():
@@ -364,7 +368,7 @@
         myjitdriver = JitDriver(greens = ['pos'], reds = ['i', 'j', 'n', 'x'])
         bytecode = "IzJxji"
         def f(n, threshold):
-            myjitdriver.set_param('threshold', threshold)        
+            set_param(myjitdriver, 'threshold', threshold)        
             i = j = x = 0
             pos = 0
             op = '-'
@@ -411,7 +415,7 @@
         myjitdriver = JitDriver(greens = ['pos'], reds = ['i', 'j', 'n', 'x'])
         bytecode = "IzJxji"
         def f(nval, threshold):
-            myjitdriver.set_param('threshold', threshold)        
+            set_param(myjitdriver, 'threshold', threshold)        
             i, j, x = A(0), A(0), A(0)
             n = A(nval)
             pos = 0
@@ -643,8 +647,12 @@
         res = self.meta_interp(main_interpreter_loop, [1])
         assert res == 102
         self.check_loop_count(1)
-        self.check_loops({'int_add' : 3, 'int_gt' : 1,
-                          'guard_false' : 1, 'jump' : 1})
+        if 'unroll' in self.enable_opts:
+            self.check_resops({'int_add' : 6, 'int_gt' : 2,
+                               'guard_false' : 2, 'jump' : 2})
+        else:
+            self.check_resops({'int_add' : 3, 'int_gt' : 1,
+                               'guard_false' : 1, 'jump' : 1})
 
     def test_automatic_promotion(self):
         myjitdriver = JitDriver(greens = ['i'],
@@ -686,7 +694,7 @@
         self.check_loop_count(1)
         # These loops do different numbers of ops based on which optimizer we
         # are testing with.
-        self.check_loops(self.automatic_promotion_result)
+        self.check_resops(self.automatic_promotion_result)
 
     def test_can_enter_jit_outside_main_loop(self):
         myjitdriver = JitDriver(greens=[], reds=['i', 'j', 'a'])
diff --git a/pypy/jit/metainterp/test/test_loop_unroll.py b/pypy/jit/metainterp/test/test_loop_unroll.py
--- a/pypy/jit/metainterp/test/test_loop_unroll.py
+++ b/pypy/jit/metainterp/test/test_loop_unroll.py
@@ -8,7 +8,8 @@
     enable_opts = ALL_OPTS_NAMES
     
     automatic_promotion_result = {
-        'int_add' : 3, 'int_gt' : 1, 'guard_false' : 1, 'jump' : 1, 
+        'int_gt': 2, 'guard_false': 2, 'jump': 2, 'int_add': 6,
+        'guard_value': 1        
     }
 
     # ====> test_loop.py
diff --git a/pypy/jit/metainterp/test/test_quasiimmut.py b/pypy/jit/metainterp/test/test_quasiimmut.py
--- a/pypy/jit/metainterp/test/test_quasiimmut.py
+++ b/pypy/jit/metainterp/test/test_quasiimmut.py
@@ -73,8 +73,7 @@
         #
         res = self.meta_interp(f, [100, 7])
         assert res == 700
-        self.check_loops(guard_not_invalidated=2, getfield_gc=0,
-                         everywhere=True)
+        self.check_resops(guard_not_invalidated=2, getfield_gc=0)
         #
         from pypy.jit.metainterp.warmspot import get_stats
         loops = get_stats().loops
@@ -103,7 +102,7 @@
         assert f(100, 7) == 721
         res = self.meta_interp(f, [100, 7])
         assert res == 721
-        self.check_loops(guard_not_invalidated=0, getfield_gc=1)
+        self.check_resops(guard_not_invalidated=0, getfield_gc=3)
         #
         from pypy.jit.metainterp.warmspot import get_stats
         loops = get_stats().loops
@@ -134,8 +133,7 @@
         #
         res = self.meta_interp(f, [100, 7])
         assert res == 700
-        self.check_loops(guard_not_invalidated=2, getfield_gc=0,
-                         everywhere=True)
+        self.check_resops(guard_not_invalidated=2, getfield_gc=0)
 
     def test_change_during_tracing_1(self):
         myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total'])
@@ -160,7 +158,7 @@
         assert f(100, 7) == 721
         res = self.meta_interp(f, [100, 7])
         assert res == 721
-        self.check_loops(guard_not_invalidated=0, getfield_gc=1)
+        self.check_resops(guard_not_invalidated=0, getfield_gc=2)
 
     def test_change_during_tracing_2(self):
         myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total'])
@@ -186,7 +184,7 @@
         assert f(100, 7) == 700
         res = self.meta_interp(f, [100, 7])
         assert res == 700
-        self.check_loops(guard_not_invalidated=0, getfield_gc=1)
+        self.check_resops(guard_not_invalidated=0, getfield_gc=2)
 
     def test_change_invalidate_reentering(self):
         myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total'])
@@ -212,7 +210,7 @@
         assert g(100, 7) == 700707
         res = self.meta_interp(g, [100, 7])
         assert res == 700707
-        self.check_loops(guard_not_invalidated=2, getfield_gc=0)
+        self.check_resops(guard_not_invalidated=4, getfield_gc=0)
 
     def test_invalidate_while_running(self):
         jitdriver = JitDriver(greens=['foo'], reds=['i', 'total'])
@@ -324,8 +322,8 @@
         assert f(100, 15) == 3009
         res = self.meta_interp(f, [100, 15])
         assert res == 3009
-        self.check_loops(guard_not_invalidated=4, getfield_gc=0,
-                         call_may_force=0, guard_not_forced=0)
+        self.check_resops(guard_not_invalidated=8, guard_not_forced=0,
+                          call_may_force=0, getfield_gc=0)
 
     def test_list_simple_1(self):
         myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total'])
@@ -347,9 +345,8 @@
         #
         res = self.meta_interp(f, [100, 7])
         assert res == 700
-        self.check_loops(guard_not_invalidated=2, getfield_gc=0,
-                         getarrayitem_gc=0, getarrayitem_gc_pure=0,
-                         everywhere=True)
+        self.check_resops(getarrayitem_gc_pure=0, guard_not_invalidated=2,
+                          getarrayitem_gc=0, getfield_gc=0)
         #
         from pypy.jit.metainterp.warmspot import get_stats
         loops = get_stats().loops
@@ -385,9 +382,8 @@
         #
         res = self.meta_interp(f, [100, 7])
         assert res == 714
-        self.check_loops(guard_not_invalidated=2, getfield_gc=0,
-                         getarrayitem_gc=0, getarrayitem_gc_pure=0,
-                         arraylen_gc=0, everywhere=True)
+        self.check_resops(getarrayitem_gc_pure=0, guard_not_invalidated=2,
+                          arraylen_gc=0, getarrayitem_gc=0, getfield_gc=0)
         #
         from pypy.jit.metainterp.warmspot import get_stats
         loops = get_stats().loops
@@ -421,9 +417,8 @@
         #
         res = self.meta_interp(f, [100, 7])
         assert res == 700
-        self.check_loops(guard_not_invalidated=2, getfield_gc=0,
-                         getarrayitem_gc=0, getarrayitem_gc_pure=0,
-                         everywhere=True)
+        self.check_resops(guard_not_invalidated=2, getfield_gc=0,
+                          getarrayitem_gc=0, getarrayitem_gc_pure=0)
         #
         from pypy.jit.metainterp.warmspot import get_stats
         loops = get_stats().loops
@@ -460,9 +455,9 @@
         assert f(100, 15) == 3009
         res = self.meta_interp(f, [100, 15])
         assert res == 3009
-        self.check_loops(guard_not_invalidated=4, getfield_gc=0,
-                         getarrayitem_gc=0, getarrayitem_gc_pure=0,
-                         call_may_force=0, guard_not_forced=0)
+        self.check_resops(call_may_force=0, getfield_gc=0,
+                          getarrayitem_gc_pure=0, guard_not_forced=0,
+                          getarrayitem_gc=0, guard_not_invalidated=8)
 
     def test_invalidated_loop_is_not_used_any_more_as_target(self):
         myjitdriver = JitDriver(greens=['foo'], reds=['x'])
diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py
--- a/pypy/jit/metainterp/test/test_recursive.py
+++ b/pypy/jit/metainterp/test/test_recursive.py
@@ -1,5 +1,5 @@
 import py
-from pypy.rlib.jit import JitDriver, we_are_jitted, hint
+from pypy.rlib.jit import JitDriver, hint, set_param
 from pypy.rlib.jit import unroll_safe, dont_look_inside, promote
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.debug import fatalerror
@@ -143,11 +143,11 @@
         f = self.get_interpreter(codes)
 
         assert self.meta_interp(f, [0, 0, 0], enable_opts='') == 42
-        self.check_loops(int_add = 1, call_may_force = 1, call = 0)
+        self.check_resops(call_may_force=1, int_add=1, call=0)
         assert self.meta_interp(f, [0, 0, 0], enable_opts='',
                                 inline=True) == 42
-        self.check_loops(int_add = 2, call_may_force = 0, call = 0,
-                         guard_no_exception = 0)
+        self.check_resops(call=0, int_add=2, call_may_force=0,
+                          guard_no_exception=0)
 
     def test_inline_jitdriver_check(self):
         code = "021"
@@ -160,7 +160,7 @@
                                 inline=True) == 42
         # the call is fully inlined, because we jump to subcode[1], thus
         # skipping completely the JUMP_BACK in subcode[0]
-        self.check_loops(call_may_force = 0, call_assembler = 0, call = 0)
+        self.check_resops(call=0, call_may_force=0, call_assembler=0)
 
     def test_guard_failure_in_inlined_function(self):
         def p(pc, code):
@@ -308,8 +308,8 @@
                 pc += 1
             return n
         def main(n):
-            myjitdriver.set_param('threshold', 3)
-            myjitdriver.set_param('trace_eagerness', 5)            
+            set_param(None, 'threshold', 3)
+            set_param(None, 'trace_eagerness', 5)            
             return f("c-l", n)
         expected = main(100)
         res = self.meta_interp(main, [100], enable_opts='', inline=True)
@@ -329,7 +329,7 @@
                 return recursive(n - 1) + 1
             return 0
         def loop(n):            
-            myjitdriver.set_param("threshold", 10)
+            set_param(myjitdriver, "threshold", 10)
             pc = 0
             while n:
                 myjitdriver.can_enter_jit(n=n)
@@ -351,8 +351,8 @@
             return 0
         myjitdriver = JitDriver(greens=[], reds=['n'])
         def loop(n):
-            myjitdriver.set_param("threshold", 4)
-            myjitdriver.set_param("trace_eagerness", 2)
+            set_param(None, "threshold", 4)
+            set_param(None, "trace_eagerness", 2)
             while n:
                 myjitdriver.can_enter_jit(n=n)
                 myjitdriver.jit_merge_point(n=n)
@@ -482,19 +482,19 @@
         TRACE_LIMIT = 66
  
         def main(inline):
-            myjitdriver.set_param("threshold", 10)
-            myjitdriver.set_param('function_threshold', 60)
+            set_param(None, "threshold", 10)
+            set_param(None, 'function_threshold', 60)
             if inline:
-                myjitdriver.set_param('inlining', True)
+                set_param(None, 'inlining', True)
             else:
-                myjitdriver.set_param('inlining', False)
+                set_param(None, 'inlining', False)
             return loop(100)
 
         res = self.meta_interp(main, [0], enable_opts='', trace_limit=TRACE_LIMIT)
-        self.check_loops(call_may_force=1, call=0)
+        self.check_resops(call=0, call_may_force=1)
 
         res = self.meta_interp(main, [1], enable_opts='', trace_limit=TRACE_LIMIT)
-        self.check_loops(call_may_force=0, call=0)
+        self.check_resops(call=0, call_may_force=0)
 
     def test_trace_from_start(self):
         def p(pc, code):
@@ -564,11 +564,11 @@
                 pc += 1
             return n
         def g(m):
-            myjitdriver.set_param('inlining', True)
+            set_param(None, 'inlining', True)
             # carefully chosen threshold to make sure that the inner function
             # cannot be inlined, but the inner function on its own is small
             # enough
-            myjitdriver.set_param('trace_limit', 40)
+            set_param(None, 'trace_limit', 40)
             if m > 1000000:
                 f('', 0)
             result = 0
@@ -576,7 +576,7 @@
                 result += f('-c-----------l-', i+100)
         self.meta_interp(g, [10], backendopt=True)
         self.check_aborted_count(1)
-        self.check_loops(call_assembler=1, call=0)
+        self.check_resops(call=0, call_assembler=2)        
         self.check_tree_loop_count(3)
 
     def test_directly_call_assembler(self):
@@ -625,8 +625,7 @@
         try:
             compile.compile_tmp_callback = my_ctc
             self.meta_interp(portal, [2, 5], inline=True)
-            self.check_loops(call_assembler=2, call_may_force=0,
-                             everywhere=True)
+            self.check_resops(call_may_force=0, call_assembler=2)
         finally:
             compile.compile_tmp_callback = original_ctc
         # check that we made a temporary callback
@@ -681,8 +680,7 @@
         try:
             compile.compile_tmp_callback = my_ctc
             self.meta_interp(main, [2, 5], inline=True)
-            self.check_loops(call_assembler=2, call_may_force=0,
-                             everywhere=True)
+            self.check_resops(call_may_force=0, call_assembler=2)
         finally:
             compile.compile_tmp_callback = original_ctc
         # check that we made a temporary callback
@@ -1021,7 +1019,7 @@
         res = self.meta_interp(portal, [2, 0], inline=True,
                                policy=StopAtXPolicy(residual))
         assert res == portal(2, 0)
-        self.check_loops(call_assembler=4, everywhere=True)
+        self.check_resops(call_assembler=4)
 
     def test_inline_without_hitting_the_loop(self):
         driver = JitDriver(greens = ['codeno'], reds = ['i'],
@@ -1045,7 +1043,7 @@
         assert portal(0) == 70
         res = self.meta_interp(portal, [0], inline=True)
         assert res == 70
-        self.check_loops(call_assembler=0)
+        self.check_resops(call_assembler=0)
 
     def test_inline_with_hitting_the_loop_sometimes(self):
         driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'],
@@ -1071,7 +1069,7 @@
         assert portal(0, 1) == 2095
         res = self.meta_interp(portal, [0, 1], inline=True)
         assert res == 2095
-        self.check_loops(call_assembler=12, everywhere=True)
+        self.check_resops(call_assembler=12)
 
     def test_inline_with_hitting_the_loop_sometimes_exc(self):
         driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'],
@@ -1109,7 +1107,7 @@
         assert main(0, 1) == 2095
         res = self.meta_interp(main, [0, 1], inline=True)
         assert res == 2095
-        self.check_loops(call_assembler=12, everywhere=True)
+        self.check_resops(call_assembler=12)
 
     def test_handle_jitexception_in_portal(self):
         # a test for _handle_jitexception_in_portal in blackhole.py
@@ -1207,9 +1205,9 @@
                     driver.can_enter_jit(c=c, i=i, v=v)
                 break
 
-        def main(c, i, set_param, v):
-            if set_param:
-                driver.set_param('function_threshold', 0)
+        def main(c, i, _set_param, v):
+            if _set_param:
+                set_param(driver, 'function_threshold', 0)
             portal(c, i, v)
 
         self.meta_interp(main, [10, 10, False, False], inline=True)
@@ -1238,7 +1236,7 @@
                 i += 1
 
         self.meta_interp(portal, [0, 0, 0], inline=True)
-        self.check_loops(call=0, call_may_force=0)
+        self.check_resops(call_may_force=0, call=0)
 
 class TestLLtype(RecursiveTests, LLJitMixin):
     pass
diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py
--- a/pypy/jit/metainterp/test/test_resume.py
+++ b/pypy/jit/metainterp/test/test_resume.py
@@ -23,11 +23,11 @@
     assert tag(-3, 2) == rffi.r_short(-3<<2|2)
     assert tag((1<<13)-1, 3) == rffi.r_short(((1<<15)-1)|3)
     assert tag(-1<<13, 3) == rffi.r_short((-1<<15)|3)
-    py.test.raises(ValueError, tag, 3, 5)
-    py.test.raises(ValueError, tag, 1<<13, 0)
-    py.test.raises(ValueError, tag, (1<<13)+1, 0)
-    py.test.raises(ValueError, tag, (-1<<13)-1, 0)
-    py.test.raises(ValueError, tag, (-1<<13)-5, 0)
+    py.test.raises(AssertionError, tag, 3, 5)
+    py.test.raises(TagOverflow, tag, 1<<13, 0)
+    py.test.raises(TagOverflow, tag, (1<<13)+1, 0)
+    py.test.raises(TagOverflow, tag, (-1<<13)-1, 0)
+    py.test.raises(TagOverflow, tag, (-1<<13)-5, 0)
 
 def test_untag():
     assert untag(tag(3, 1)) == (3, 1)
@@ -1318,8 +1318,7 @@
     assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062
     assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647
     #
-    from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole
-    py.test.raises(SwitchToBlackhole, modifier._add_pending_fields,
+    py.test.raises(TagOverflow, modifier._add_pending_fields,
                    [(array_a, 42, 63, 2147483648)])
 
 def test_resume_reader_fields_and_arrayitems():
diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py
--- a/pypy/jit/metainterp/test/test_send.py
+++ b/pypy/jit/metainterp/test/test_send.py
@@ -20,9 +20,8 @@
             return c
         res = self.meta_interp(f, [1])
         assert res == 2
-        self.check_loops({'jump': 1,
-                          'int_sub': 1, 'int_gt' : 1,
-                          'guard_true': 1})    # all folded away
+        self.check_resops({'jump': 2, 'guard_true': 2, 'int_gt': 2,
+                           'int_sub': 2}) # all folded away
 
     def test_red_builtin_send(self):
         myjitdriver = JitDriver(greens = [], reds = ['i', 'counter'])
@@ -41,12 +40,9 @@
             return res
         res = self.meta_interp(f, [1], policy=StopAtXPolicy(externfn))
         assert res == 2
-        if self.type_system == 'ootype':
-            self.check_loops(call=1, oosend=1) # 'len' remains
-        else:
-            # 'len' becomes a getfield('num_items') for now in lltype,
-            # which is itself encoded as a 'getfield_gc'
-            self.check_loops(call=1, getfield_gc=1)
+        # 'len' becomes a getfield('num_items') for now in lltype,
+        # which is itself encoded as a 'getfield_gc'
+        self.check_resops(call=2, getfield_gc=2)
 
     def test_send_to_single_target_method(self):
         myjitdriver = JitDriver(greens = [], reds = ['i', 'counter'])
@@ -70,11 +66,10 @@
         res = self.meta_interp(f, [1], policy=StopAtXPolicy(externfn),
                                backendopt=True)
         assert res == 43
-        self.check_loops({'call': 1, 'guard_no_exception': 1,
-                          'getfield_gc': 1,
-                          'int_add': 1,
-                          'jump': 1, 'int_gt' : 1, 'guard_true' : 1,
-                          'int_sub' : 1})
+        self.check_resops({'int_gt': 2, 'getfield_gc': 2,
+                           'guard_true': 2, 'int_sub': 2, 'jump': 2,
+                           'call': 2, 'guard_no_exception': 2,
+                           'int_add': 2})
 
     def test_red_send_to_green_receiver(self):
         myjitdriver = JitDriver(greens = ['i'], reds = ['counter', 'j'])
@@ -97,7 +92,7 @@
             return res
         res = self.meta_interp(f, [4, -1])
         assert res == 145
-        self.check_loops(int_add = 1, everywhere=True)
+        self.check_resops(int_add=1)
 
     def test_oosend_base(self):
         myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'w'])
@@ -132,7 +127,7 @@
         assert res == 17
         res = self.meta_interp(f, [4, 14])
         assert res == 1404
-        self.check_loops(guard_class=0, new_with_vtable=0, new=0)
+        self.check_resops(guard_class=1, new=0, new_with_vtable=0)
 
     def test_three_receivers(self):
         myjitdriver = JitDriver(greens = [], reds = ['y'])
@@ -205,8 +200,7 @@
         # of the body in a single bigger loop with no failing guard except
         # the final one.
         self.check_loop_count(1)
-        self.check_loops(guard_class=0,
-                                int_add=2, int_sub=2)
+        self.check_resops(guard_class=1, int_add=4, int_sub=4)
         self.check_jumps(14)
 
     def test_oosend_guard_failure_2(self):
@@ -247,8 +241,7 @@
         res = self.meta_interp(f, [4, 28])
         assert res == f(4, 28)
         self.check_loop_count(1)
-        self.check_loops(guard_class=0,
-                                int_add=2, int_sub=2)
+        self.check_resops(guard_class=1, int_add=4, int_sub=4)
         self.check_jumps(14)
 
     def test_oosend_different_initial_class(self):
@@ -285,8 +278,8 @@
         # However, this doesn't match the initial value of 'w'.
         # XXX This not completely easy to check...
         self.check_loop_count(1)
-        self.check_loops(int_add=0, int_lshift=1, guard_class=0,
-                         new_with_vtable=0, new=0)
+        self.check_resops(guard_class=1, new_with_vtable=0, int_lshift=2,
+                          int_add=0, new=0)
 
     def test_indirect_call_unknown_object_1(self):
         myjitdriver = JitDriver(greens = [], reds = ['x', 'y'])
@@ -566,10 +559,7 @@
         policy = StopAtXPolicy(new, A.foo.im_func, B.foo.im_func)
         res = self.meta_interp(fn, [0, 20], policy=policy)
         assert res == 42
-        if self.type_system == 'ootype':
-            self.check_loops(oosend=1)
-        else:
-            self.check_loops(call=1)
+        self.check_resops(call=2)
 
 
     def test_residual_oosend_with_void(self):
@@ -597,10 +587,7 @@
         policy = StopAtXPolicy(new, A.foo.im_func)
         res = self.meta_interp(fn, [1, 20], policy=policy)
         assert res == 41
-        if self.type_system == 'ootype':
-            self.check_loops(oosend=1)
-        else:
-            self.check_loops(call=1)
+        self.check_resops(call=2)
 
     def test_constfold_pure_oosend(self):
         myjitdriver = JitDriver(greens=[], reds = ['i', 'obj'])
@@ -621,10 +608,7 @@
         policy = StopAtXPolicy(A.foo.im_func)
         res = self.meta_interp(fn, [1, 20], policy=policy)
         assert res == 42
-        if self.type_system == 'ootype':
-            self.check_loops(oosend=0)
-        else:
-            self.check_loops(call=0)
+        self.check_resops(call=0)
 
     def test_generalize_loop(self):
         myjitdriver = JitDriver(greens=[], reds = ['i', 'obj'])
diff --git a/pypy/jit/metainterp/test/test_slist.py b/pypy/jit/metainterp/test/test_slist.py
--- a/pypy/jit/metainterp/test/test_slist.py
+++ b/pypy/jit/metainterp/test/test_slist.py
@@ -76,7 +76,7 @@
             return lst[i]
         res = self.meta_interp(f, [21], listops=True)
         assert res == f(21)
-        self.check_loops(call=0)
+        self.check_resops(call=0)
 
     def test_getitem_neg(self):
         myjitdriver = JitDriver(greens = [], reds = ['i', 'n'])
@@ -92,7 +92,7 @@
             return x
         res = self.meta_interp(f, [-2], listops=True)
         assert res == 41
-        self.check_loops(call=0, guard_value=0)
+        self.check_resops(call=0, guard_value=0)
 
 # we don't support resizable lists on ootype
 #class TestOOtype(ListTests, OOJitMixin):
diff --git a/pypy/jit/metainterp/test/test_string.py b/pypy/jit/metainterp/test/test_string.py
--- a/pypy/jit/metainterp/test/test_string.py
+++ b/pypy/jit/metainterp/test/test_string.py
@@ -30,7 +30,7 @@
             return i
         res = self.meta_interp(f, [10, True, _str('h')], listops=True)
         assert res == 5
-        self.check_loops(**{self.CALL: 1, self.CALL_PURE: 0, 'everywhere': True})
+        self.check_resops(**{self.CALL: 1, self.CALL_PURE: 0})
 
     def test_eq_folded(self):
         _str = self._str
@@ -50,7 +50,7 @@
             return i
         res = self.meta_interp(f, [10, True, _str('h')], listops=True)
         assert res == 5
-        self.check_loops(**{self.CALL: 0, self.CALL_PURE: 0})
+        self.check_resops(**{self.CALL: 0, self.CALL_PURE: 0})
 
     def test_newstr(self):
         _str, _chr = self._str, self._chr
@@ -85,7 +85,7 @@
                 n -= 1
             return 42
         self.meta_interp(f, [6])
-        self.check_loops(newstr=0, strsetitem=0, strlen=0,
+        self.check_resops(newstr=0, strsetitem=0, strlen=0,
                          newunicode=0, unicodesetitem=0, unicodelen=0)
 
     def test_char2string_escape(self):
@@ -126,7 +126,7 @@
             return total
         res = self.meta_interp(f, [6])
         assert res == 21
-        self.check_loops(newstr=0, strgetitem=0, strsetitem=0, strlen=0,
+        self.check_resops(newstr=0, strgetitem=0, strsetitem=0, strlen=0,
                          newunicode=0, unicodegetitem=0, unicodesetitem=0,
                          unicodelen=0)
 
@@ -147,7 +147,7 @@
                 m -= 1
             return 42
         self.meta_interp(f, [6, 7])
-        self.check_loops(newstr=0, strsetitem=0,
+        self.check_resops(newstr=0, strsetitem=0,
                          newunicode=0, unicodesetitem=0,
                          call=0, call_pure=0)
 
@@ -168,12 +168,11 @@
             return 42
         self.meta_interp(f, [6, 7])
         if _str is str:
-            self.check_loops(newstr=1, strsetitem=0, copystrcontent=2,
-                             call=1, call_pure=0)   # escape
+            self.check_resops(call_pure=0, copystrcontent=4,
+                              strsetitem=0, call=2, newstr=2)
         else:
-            self.check_loops(newunicode=1, unicodesetitem=0,
-                             copyunicodecontent=2,
-                             call=1, call_pure=0)   # escape
+            self.check_resops(call_pure=0, unicodesetitem=0, call=2,
+                              copyunicodecontent=4, newunicode=2)
 
     def test_strconcat_escape_str_char(self):
         _str, _chr = self._str, self._chr
@@ -192,12 +191,11 @@
             return 42
         self.meta_interp(f, [6, 7])
         if _str is str:
-            self.check_loops(newstr=1, strsetitem=1, copystrcontent=1,
-                             call=1, call_pure=0)   # escape
+            self.check_resops(call_pure=0, copystrcontent=2, strsetitem=2,
+                              call=2, newstr=2)
         else:
-            self.check_loops(newunicode=1, unicodesetitem=1,
-                             copyunicodecontent=1,
-                             call=1, call_pure=0)   # escape
+            self.check_resops(call_pure=0, unicodesetitem=2, call=2,
+                              copyunicodecontent=2, newunicode=2)
 
     def test_strconcat_escape_char_str(self):
         _str, _chr = self._str, self._chr
@@ -216,12 +214,11 @@
             return 42
         self.meta_interp(f, [6, 7])
         if _str is str:
-            self.check_loops(newstr=1, strsetitem=1, copystrcontent=1,
-                             call=1, call_pure=0)   # escape
+            self.check_resops(call_pure=0, copystrcontent=2,
+                              strsetitem=2, call=2, newstr=2)
         else:
-            self.check_loops(newunicode=1, unicodesetitem=1,
-                             copyunicodecontent=1,
-                             call=1, call_pure=0)   # escape
+            self.check_resops(call_pure=0, unicodesetitem=2, call=2,
+                              copyunicodecontent=2, newunicode=2)
 
     def test_strconcat_escape_char_char(self):
         _str, _chr = self._str, self._chr
@@ -239,12 +236,11 @@
             return 42
         self.meta_interp(f, [6, 7])
         if _str is str:
-            self.check_loops(newstr=1, strsetitem=2, copystrcontent=0,
-                             call=1, call_pure=0)   # escape
+            self.check_resops(call_pure=0, copystrcontent=0,
+                              strsetitem=4, call=2, newstr=2)
         else:
-            self.check_loops(newunicode=1, unicodesetitem=2,
-                             copyunicodecontent=0,
-                             call=1, call_pure=0)   # escape
+            self.check_resops(call_pure=0, unicodesetitem=4, call=2,
+                              copyunicodecontent=0, newunicode=2)
 
     def test_strconcat_escape_str_char_str(self):
         _str, _chr = self._str, self._chr
@@ -263,12 +259,11 @@
             return 42
         self.meta_interp(f, [6, 7])
         if _str is str:
-            self.check_loops(newstr=1, strsetitem=1, copystrcontent=2,
-                             call=1, call_pure=0)   # escape
+            self.check_resops(call_pure=0, copystrcontent=4, strsetitem=2,
+                              call=2, newstr=2)
         else:
-            self.check_loops(newunicode=1, unicodesetitem=1,
-                             copyunicodecontent=2,
-                             call=1, call_pure=0)   # escape
+            self.check_resops(call_pure=0, unicodesetitem=2, call=2,
+                              copyunicodecontent=4, newunicode=2)
 
     def test_strconcat_guard_fail(self):
         _str = self._str
@@ -325,7 +320,7 @@
                 m -= 1
             return 42
         self.meta_interp(f, [6, 7])
-        self.check_loops(newstr=0, newunicode=0)
+        self.check_resops(newunicode=0, newstr=0)
 
     def test_str_slice_len_surviving(self):
         _str = self._str
@@ -491,7 +486,7 @@
             def __init__(self, s):
                 self.defaultencoding = s
         _str = self._str
-        sys = Sys(_str('ascii'))        
+        sys = Sys(_str('ascii'))
         mydriver = JitDriver(reds = ['n', 'sa'], greens = [])
         def f(n):
             sa = 0
@@ -504,13 +499,13 @@
             sys.defaultencoding = _str('utf-8')
             return sa
         assert self.meta_interp(f, [8]) == f(8)
-        self.check_loops({'int_add': 1, 'guard_true': 1, 'int_sub': 1,
-                          'jump': 1, 'int_is_true': 1,
-                          'guard_not_invalidated': 1})
+        self.check_resops({'jump': 2, 'int_is_true': 2, 'int_add': 2,
+                           'guard_true': 2, 'guard_not_invalidated': 2,
+                           'int_sub': 2})
 
     def test_promote_string(self):
         driver = JitDriver(greens = [], reds = ['n'])
-        
+
         def f(n):
             while n < 21:
                 driver.jit_merge_point(n=n)
@@ -519,7 +514,7 @@
             return 0
 
         self.meta_interp(f, [0])
-        self.check_loops(call=3 + 1) # one for int2str
+        self.check_resops(call=7)
 
 #class TestOOtype(StringTests, OOJitMixin):
 #    CALL = "oosend"
@@ -552,9 +547,8 @@
                 m -= 1
             return 42
         self.meta_interp(f, [6, 7])
-        self.check_loops(call=1,    # escape()
-                         newunicode=1, unicodegetitem=0,
-                         unicodesetitem=1, copyunicodecontent=1)
+        self.check_resops(unicodesetitem=2, newunicode=2, call=4,
+                          copyunicodecontent=2, unicodegetitem=0)
 
     def test_str2unicode_fold(self):
         _str = self._str
@@ -572,9 +566,9 @@
                 m -= 1
             return 42
         self.meta_interp(f, [6, 7])
-        self.check_loops(call_pure=0, call=1,
-                         newunicode=0, unicodegetitem=0,
-                         unicodesetitem=0, copyunicodecontent=0)
+        self.check_resops(call_pure=0, unicodesetitem=0, call=2,
+                          newunicode=0, unicodegetitem=0,
+                          copyunicodecontent=0)
 
     def test_join_chars(self):
         jitdriver = JitDriver(reds=['a', 'b', 'c', 'i'], greens=[])
@@ -596,9 +590,8 @@
         # The "".join should be unrolled, since the length of x is known since
         # it is virtual, ensure there are no calls to ll_join_chars, or
         # allocations.
-        self.check_loops({
-            "guard_true": 5, "int_is_true": 3, "int_lt": 2, "int_add": 2, "jump": 2,
-        }, everywhere=True)
+        self.check_resops({'jump': 2, 'guard_true': 5, 'int_lt': 2,
+                           'int_add': 2, 'int_is_true': 3})
 
     def test_virtual_copystringcontent(self):
         jitdriver = JitDriver(reds=['n', 'result'], greens=[])
diff --git a/pypy/jit/metainterp/test/test_tl.py b/pypy/jit/metainterp/test/test_tl.py
--- a/pypy/jit/metainterp/test/test_tl.py
+++ b/pypy/jit/metainterp/test/test_tl.py
@@ -72,16 +72,16 @@
         res = self.meta_interp(main, [0, 6], listops=True,
                                backendopt=True)
         assert res == 5040
-        self.check_loops({'int_mul':1, 'jump':1,
-                          'int_sub':1, 'int_le':1, 'guard_false':1})
+        self.check_resops({'jump': 2, 'int_le': 2, 'guard_value': 1,
+                           'int_mul': 2, 'guard_false': 2, 'int_sub': 2})
 
     def test_tl_2(self):
         main = self._get_main()
         res = self.meta_interp(main, [1, 10], listops=True,
                                backendopt=True)
         assert res == main(1, 10)
-        self.check_loops({'int_sub':1, 'int_le':1,
-                          'guard_false':1, 'jump':1})
+        self.check_resops({'int_le': 2, 'int_sub': 2, 'jump': 2,
+                           'guard_false': 2, 'guard_value': 1})
 
     def test_tl_call(self, listops=True, policy=None):
         from pypy.jit.tl.tl import interp
diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py
--- a/pypy/jit/metainterp/test/test_tracingopts.py
+++ b/pypy/jit/metainterp/test/test_tracingopts.py
@@ -593,6 +593,32 @@
         res = self.interp_operations(fn, [sys.maxint])
         assert res == 12
 
+    def test_opaque_list(self):
+        from pypy.rlib.rerased import new_erasing_pair
+        erase, unerase = new_erasing_pair("test_opaque_list")
+        def fn(n, ca, cb):
+            l1 = [n]
+            l2 = [n]
+            a1 = erase(l1)
+            a2 = erase(l1)
+            a = a1
+            if ca:
+                a = a2
+                if n < -100:
+                    unerase(a).append(5)
+            b = a1
+            if cb:
+                b = a
+            return unerase(a)[0] + unerase(b)[0]
+        res = self.interp_operations(fn, [7, 0, 1])
+        assert res == 7 * 2
+        self.check_operations_history(getarrayitem_gc=0,
+                getfield_gc=0)
+        res = self.interp_operations(fn, [-7, 1, 1])
+        assert res == -7 * 2
+        self.check_operations_history(getarrayitem_gc=0,
+                getfield_gc=0)
+
     def test_copy_str_content(self):
         def fn(n):
             a = StringBuilder()
@@ -601,4 +627,4 @@
             return x[0]
         res = self.interp_operations(fn, [0])
         assert res == 1
-        self.check_operations_history(getarrayitem_gc=0, getarrayitem_gc_pure=0 )
\ No newline at end of file
+        self.check_operations_history(getarrayitem_gc=0, getarrayitem_gc_pure=0)
diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py
--- a/pypy/jit/metainterp/test/test_virtual.py
+++ b/pypy/jit/metainterp/test/test_virtual.py
@@ -31,8 +31,9 @@
         res = self.meta_interp(f, [10])
         assert res == 55 * 10
         self.check_loop_count(1)
-        self.check_loops(new=0, new_with_vtable=0,
-                                getfield_gc=0, setfield_gc=0)
+        self.check_resops(new_with_vtable=0, setfield_gc=0,
+                          getfield_gc=2, new=0)
+
 
     def test_virtualized2(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'node1', 'node2'])
@@ -53,8 +54,8 @@
                 n -= 1
             return node1.value * node2.value
         assert f(10) == self.meta_interp(f, [10])
-        self.check_loops(new=0, new_with_vtable=0,
-                         getfield_gc=0, setfield_gc=0)
+        self.check_resops(new_with_vtable=0, setfield_gc=0, getfield_gc=2,
+                          new=0)
 
     def test_virtualized_circular1(self):
         class MyNode():
@@ -79,8 +80,8 @@
         res = self.meta_interp(f, [10])
         assert res == 55 * 10
         self.check_loop_count(1)
-        self.check_loops(new=0, new_with_vtable=0,
-                                getfield_gc=0, setfield_gc=0)
+        self.check_resops(new_with_vtable=0, setfield_gc=0,
+                          getfield_gc=3, new=0)
 
     def test_virtualized_float(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'node'])
@@ -97,7 +98,7 @@
         res = self.meta_interp(f, [10])
         assert res == f(10)
         self.check_loop_count(1)
-        self.check_loops(new=0, float_add=0)
+        self.check_resops(new=0, float_add=1)
 
     def test_virtualized_float2(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'node'])
@@ -115,7 +116,8 @@
         res = self.meta_interp(f, [10])
         assert res == f(10)
         self.check_loop_count(1)
-        self.check_loops(new=0, float_add=1)
+        self.check_resops(new=0, float_add=2)
+
 
     def test_virtualized_2(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'node'])
@@ -139,8 +141,8 @@
         res = self.meta_interp(f, [10])
         assert res == 55 * 30
         self.check_loop_count(1)
-        self.check_loops(new=0, new_with_vtable=0,
-                                getfield_gc=0, setfield_gc=0)
+        self.check_resops(new_with_vtable=0, setfield_gc=0, getfield_gc=2,
+                          new=0)
 
     def test_nonvirtual_obj_delays_loop(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'node'])
@@ -160,8 +162,8 @@
         res = self.meta_interp(f, [500])
         assert res == 640
         self.check_loop_count(1)
-        self.check_loops(new=0, new_with_vtable=0,
-                                getfield_gc=0, setfield_gc=0)
+        self.check_resops(new_with_vtable=0, setfield_gc=0,
+                          getfield_gc=1, new=0)
 
     def test_two_loops_with_virtual(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'node'])
@@ -184,8 +186,9 @@
         res = self.meta_interp(f, [18])
         assert res == f(18)
         self.check_loop_count(2)
-        self.check_loops(new=0, new_with_vtable=0,
-                                getfield_gc=0, setfield_gc=0)
+        self.check_resops(new_with_vtable=0, setfield_gc=0,
+                          getfield_gc=2, new=0)
+
         
     def test_two_loops_with_escaping_virtual(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'node'])
@@ -212,8 +215,8 @@
         res = self.meta_interp(f, [20], policy=StopAtXPolicy(externfn))
         assert res == f(20)
         self.check_loop_count(3)
-        self.check_loops(**{self._new_op: 1})
-        self.check_loops(int_mul=0, call=1)
+        self.check_resops(**{self._new_op: 1})
+        self.check_resops(int_mul=0, call=1)
 
     def test_two_virtuals(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'prev'])
@@ -236,7 +239,7 @@
 
         res = self.meta_interp(f, [12])
         assert res == 78
-        self.check_loops(new_with_vtable=0, new=0)
+        self.check_resops(new_with_vtable=0, new=0)
 
     def test_specialied_bridge(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
@@ -281,7 +284,7 @@
 
         res = self.meta_interp(f, [20])
         assert res == 9
-        self.check_loops(new_with_vtable=0, new=0)
+        self.check_resops(new_with_vtable=0, new=0)
 
     def test_immutable_constant_getfield(self):
         myjitdriver = JitDriver(greens = ['stufflist'], reds = ['n', 'i'])
@@ -307,7 +310,7 @@
 
         res = self.meta_interp(f, [10, 1, 0], listops=True)
         assert res == 0
-        self.check_loops(getfield_gc=0)
+        self.check_resops(getfield_gc=0)
 
     def test_escapes(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'parent'])
@@ -336,7 +339,7 @@
 
         res = self.meta_interp(f, [10], policy=StopAtXPolicy(g))
         assert res == 3
-        self.check_loops(**{self._new_op: 1}) 
+        self.check_resops(**{self._new_op: 1}) 
 
     def test_virtual_on_virtual(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'parent'])
@@ -366,7 +369,7 @@
 
         res = self.meta_interp(f, [10])
         assert res == 2
-        self.check_loops(new=0, new_with_vtable=0) 
+        self.check_resops(new=0, new_with_vtable=0)
 
     def test_bridge_from_interpreter(self):
         mydriver = JitDriver(reds = ['n', 'f'], greens = [])
@@ -841,7 +844,7 @@
                 del t2
             return i
         assert self.meta_interp(f, []) == 10
-        self.check_loops(new_array=0)
+        self.check_resops(new_array=0)
 
     def test_virtual_streq_bug(self):
         mydriver = JitDriver(reds = ['i', 's', 'a'], greens = [])
@@ -942,8 +945,8 @@
 
         res = self.meta_interp(f, [16])
         assert res == f(16)
-        self.check_loops(getfield_gc=2)
-        
+        self.check_resops(getfield_gc=7)
+     
 
 # ____________________________________________________________
 # Run 1: all the tests instantiate a real RPython class
@@ -985,10 +988,8 @@
         res = self.meta_interp(f, [10])
         assert res == 20
         self.check_loop_count(1)
-        self.check_loops(new=0, new_with_vtable=0,
-                                getfield_gc=0, setfield_gc=0)
-
-
+        self.check_resops(new_with_vtable=0, setfield_gc=0, getfield_gc=0,
+                          new=0)
 
 class TestOOtype_Instance(VirtualTests, OOJitMixin):
     _new_op = 'new_with_vtable'
diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py
--- a/pypy/jit/metainterp/test/test_virtualizable.py
+++ b/pypy/jit/metainterp/test/test_virtualizable.py
@@ -77,7 +77,7 @@
             return xy.inst_x
         res = self.meta_interp(f, [20])
         assert res == 30
-        self.check_loops(getfield_gc=0, setfield_gc=0)
+        self.check_resops(setfield_gc=0, getfield_gc=0)
 
     def test_preexisting_access_2(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'],
@@ -102,7 +102,7 @@
         assert f(5) == 185
         res = self.meta_interp(f, [5])
         assert res == 185
-        self.check_loops(getfield_gc=0, setfield_gc=0)
+        self.check_resops(setfield_gc=0, getfield_gc=0)
 
     def test_two_paths_access(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'],
@@ -124,7 +124,7 @@
             return xy.inst_x
         res = self.meta_interp(f, [18])
         assert res == 10118
-        self.check_loops(getfield_gc=0, setfield_gc=0)
+        self.check_resops(setfield_gc=0, getfield_gc=0)
 
     def test_synchronize_in_return(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'],
@@ -146,7 +146,7 @@
             return xy.inst_x
         res = self.meta_interp(f, [18])
         assert res == 10180
-        self.check_loops(getfield_gc=0, setfield_gc=0)
+        self.check_resops(setfield_gc=0, getfield_gc=0)
 
     def test_virtualizable_and_greens(self):
         myjitdriver = JitDriver(greens = ['m'], reds = ['n', 'xy'],
@@ -174,7 +174,7 @@
             return res
         res = self.meta_interp(f, [40])
         assert res == 50 * 4
-        self.check_loops(getfield_gc=0, setfield_gc=0)
+        self.check_resops(setfield_gc=0, getfield_gc=0)
 
     def test_double_frame(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'xy', 'other'],
@@ -197,8 +197,7 @@
             return xy.inst_x
         res = self.meta_interp(f, [20])
         assert res == 134
-        self.check_loops(getfield_gc=0, setfield_gc=1)
-        self.check_loops(getfield_gc=1, setfield_gc=2, everywhere=True)
+        self.check_resops(setfield_gc=2, getfield_gc=1)
 
     # ------------------------------
 
@@ -248,8 +247,8 @@
             return xy2.inst_l1[2]
         res = self.meta_interp(f, [16])
         assert res == 3001 + 16 * 80
-        self.check_loops(getfield_gc=0, setfield_gc=0,
-                         getarrayitem_gc=0, setarrayitem_gc=0)
+        self.check_resops(setarrayitem_gc=0, setfield_gc=0,
+                          getarrayitem_gc=0, getfield_gc=0)
 
     def test_synchronize_arrays_in_return(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'],
@@ -279,8 +278,7 @@
         assert f(18) == 10360
         res = self.meta_interp(f, [18])
         assert res == 10360
-        self.check_loops(getfield_gc=0, setfield_gc=0,
-                         getarrayitem_gc=0)
+        self.check_resops(setfield_gc=0, getarrayitem_gc=0, getfield_gc=0)
 
     def test_array_length(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'],
@@ -306,8 +304,8 @@
             return xy2.inst_l1[1]
         res = self.meta_interp(f, [18])
         assert res == 2941309 + 18
-        self.check_loops(getfield_gc=0, setfield_gc=0,
-                         getarrayitem_gc=0, arraylen_gc=0)
+        self.check_resops(setfield_gc=0, getarrayitem_gc=0,
+                          arraylen_gc=0, getfield_gc=0)
 
     def test_residual_function(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'],
@@ -340,8 +338,8 @@
             return xy2.inst_l1[1]
         res = self.meta_interp(f, [18])
         assert res == 2941309 + 18
-        self.check_loops(getfield_gc=0, setfield_gc=0,
-                         getarrayitem_gc=0, arraylen_gc=1, call=1)
+        self.check_resops(call=2, setfield_gc=0, getarrayitem_gc=0,
+                          arraylen_gc=2, getfield_gc=0)
 
     def test_double_frame_array(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2', 'other'],
@@ -377,8 +375,8 @@
         expected = f(20)
         res = self.meta_interp(f, [20], enable_opts='')
         assert res == expected
-        self.check_loops(getfield_gc=1, setfield_gc=0,
-                         arraylen_gc=1, getarrayitem_gc=1, setarrayitem_gc=1)
+        self.check_resops(setarrayitem_gc=1, setfield_gc=0,
+                          getarrayitem_gc=1, arraylen_gc=1, getfield_gc=1)
 
     # ------------------------------
 
@@ -425,8 +423,7 @@
         assert f(18) == 10360
         res = self.meta_interp(f, [18])
         assert res == 10360
-        self.check_loops(getfield_gc=0, setfield_gc=0,
-                         getarrayitem_gc=0)
+        self.check_resops(setfield_gc=0, getarrayitem_gc=0, getfield_gc=0)
 
     # ------------------------------
 
@@ -460,8 +457,7 @@
 
         res = self.meta_interp(f, [10])
         assert res == 55
-        self.check_loops(getfield_gc=0, setfield_gc=0)
-
+        self.check_resops(setfield_gc=0, getfield_gc=0)
 
     def test_virtualizable_with_array(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'x', 'frame'],
@@ -495,8 +491,7 @@
 
         res = self.meta_interp(f, [10, 1], listops=True)
         assert res == f(10, 1)
-        self.check_loops(getarrayitem_gc=0)
-
+        self.check_resops(getarrayitem_gc=0)
 
     def test_subclass_of_virtualizable(self):
         myjitdriver = JitDriver(greens = [], reds = ['frame'],
@@ -524,8 +519,7 @@
 
         res = self.meta_interp(f, [10])
         assert res == 55
-        self.check_loops(getfield_gc=0, setfield_gc=0)
-
+        self.check_resops(setfield_gc=0, getfield_gc=0)
 
     def test_external_pass(self):
         jitdriver = JitDriver(greens = [], reds = ['n', 'z', 'frame'],
@@ -1011,8 +1005,8 @@
 
         res = self.meta_interp(f, [70], listops=True)
         assert res == intmask(42 ** 70)
-        self.check_loops(int_add=0,
-                         int_sub=1)   # for 'n -= 1' only
+        self.check_resops(int_add=0,
+                          int_sub=2)   # for 'n -= 1' only
 
     def test_simple_access_directly(self):
         myjitdriver = JitDriver(greens = [], reds = ['frame'],
@@ -1043,7 +1037,7 @@
 
         res = self.meta_interp(f, [10])
         assert res == 55
-        self.check_loops(getfield_gc=0, setfield_gc=0)
+        self.check_resops(setfield_gc=0, getfield_gc=0)
 
         from pypy.jit.backend.test.support import BaseCompiledMixin
         if isinstance(self, BaseCompiledMixin):
@@ -1098,42 +1092,42 @@
 
         res = self.meta_interp(f, [10])
         assert res == 55
-        self.check_loops(new_with_vtable=0)
+        self.check_resops(new_with_vtable=0)
 
     def test_check_for_nonstandardness_only_once(self):
-         myjitdriver = JitDriver(greens = [], reds = ['frame'],
-                                 virtualizables = ['frame'])
+        myjitdriver = JitDriver(greens = [], reds = ['frame'],
+                                virtualizables = ['frame'])
 
-         class Frame(object):
-             _virtualizable2_ = ['x', 'y', 'z']
+        class Frame(object):
+            _virtualizable2_ = ['x', 'y', 'z']
 
-             def __init__(self, x, y, z=1):
-                 self = hint(self, access_directly=True)
-                 self.x = x
-                 self.y = y
-                 self.z = z
+            def __init__(self, x, y, z=1):
+                self = hint(self, access_directly=True)
+                self.x = x
+                self.y = y
+                self.z = z
 
-         class SomewhereElse:
-             pass
-         somewhere_else = SomewhereElse()
+        class SomewhereElse:
+            pass
+        somewhere_else = SomewhereElse()
 
-         def f(n):
-             frame = Frame(n, 0)
-             somewhere_else.top_frame = frame        # escapes
-             frame = hint(frame, access_directly=True)
-             while frame.x > 0:
-                 myjitdriver.can_enter_jit(frame=frame)
-                 myjitdriver.jit_merge_point(frame=frame)
-                 top_frame = somewhere_else.top_frame
-                 child_frame = Frame(frame.x, top_frame.z, 17)
-                 frame.y += child_frame.x
-                 frame.x -= top_frame.z
-             return somewhere_else.top_frame.y
- 
-         res = self.meta_interp(f, [10])
-         assert res == 55
-         self.check_loops(new_with_vtable=0, ptr_eq=1, everywhere=True)
-         self.check_history(ptr_eq=2)
+        def f(n):
+            frame = Frame(n, 0)
+            somewhere_else.top_frame = frame        # escapes
+            frame = hint(frame, access_directly=True)
+            while frame.x > 0:
+                myjitdriver.can_enter_jit(frame=frame)
+                myjitdriver.jit_merge_point(frame=frame)
+                top_frame = somewhere_else.top_frame
+                child_frame = Frame(frame.x, top_frame.z, 17)
+                frame.y += child_frame.x
+                frame.x -= top_frame.z
+            return somewhere_else.top_frame.y
+
+        res = self.meta_interp(f, [10])
+        assert res == 55
+        self.check_resops(new_with_vtable=0, ptr_eq=1)
+        self.check_history(ptr_eq=2)
 
     def test_virtual_child_frame_with_arrays(self):
         myjitdriver = JitDriver(greens = [], reds = ['frame'],
@@ -1165,7 +1159,7 @@
 
         res = self.meta_interp(f, [10], listops=True)
         assert res == 55
-        self.check_loops(new_with_vtable=0)
+        self.check_resops(new_with_vtable=0)
 
     def test_blackhole_should_not_pay_attention(self):
         myjitdriver = JitDriver(greens = [], reds = ['frame'],
@@ -1203,7 +1197,7 @@
 
         res = self.meta_interp(f, [10])
         assert res == 155
-        self.check_loops(getfield_gc=0, setfield_gc=0)
+        self.check_resops(setfield_gc=0, getfield_gc=0)
 
     def test_blackhole_should_synchronize(self):
         myjitdriver = JitDriver(greens = [], reds = ['frame'],
@@ -1239,7 +1233,7 @@
 
         res = self.meta_interp(f, [10])
         assert res == 155
-        self.check_loops(getfield_gc=0, setfield_gc=0)
+        self.check_resops(setfield_gc=0, getfield_gc=0)
 
     def test_blackhole_should_not_reenter(self):
         if not self.basic:
diff --git a/pypy/jit/metainterp/test/test_virtualref.py b/pypy/jit/metainterp/test/test_virtualref.py
--- a/pypy/jit/metainterp/test/test_virtualref.py
+++ b/pypy/jit/metainterp/test/test_virtualref.py
@@ -171,7 +171,7 @@
             return 1
         #
         self.meta_interp(f, [10])
-        self.check_loops(new_with_vtable=1)   # the vref
+        self.check_resops(new_with_vtable=2) # the vref
         self.check_aborted_count(0)
 
     def test_simple_all_removed(self):
@@ -205,8 +205,7 @@
                 virtual_ref_finish(vref, xy)
         #
         self.meta_interp(f, [15])
-        self.check_loops(new_with_vtable=0,     # all virtualized
-                         new_array=0)
+        self.check_resops(new_with_vtable=0, new_array=0)
         self.check_aborted_count(0)
 
     def test_simple_no_access(self):
@@ -242,7 +241,7 @@
                 virtual_ref_finish(vref, xy)
         #
         self.meta_interp(f, [15])
-        self.check_loops(new_with_vtable=1,     # the vref: xy doesn't need to be forced
+        self.check_resops(new_with_vtable=2,     # the vref: xy doesn't need to be forced
                          new_array=0)           # and neither xy.next1/2/3
         self.check_aborted_count(0)
 
@@ -280,8 +279,8 @@
                 exctx.topframeref = vref_None
         #
         self.meta_interp(f, [15])
-        self.check_loops(new_with_vtable=2,   # XY(), the vref
-                         new_array=3)         # next1/2/3
+        self.check_resops(new_with_vtable=4,   # XY(), the vref
+                          new_array=6)         # next1/2/3
         self.check_aborted_count(0)
 
     def test_simple_force_sometimes(self):
@@ -320,8 +319,8 @@
         #
         res = self.meta_interp(f, [30])
         assert res == 13
-        self.check_loops(new_with_vtable=1,   # the vref, but not XY()
-                         new_array=0)         # and neither next1/2/3
+        self.check_resops(new_with_vtable=2,   # the vref, but not XY()
+                          new_array=0)         # and neither next1/2/3
         self.check_loop_count(1)
         self.check_aborted_count(0)
 
@@ -362,7 +361,7 @@
         #
         res = self.meta_interp(f, [30])
         assert res == 13
-        self.check_loops(new_with_vtable=0, # all virtualized in the n!=13 loop
+        self.check_resops(new_with_vtable=0, # all virtualized in the n!=13 loop
                          new_array=0)
         self.check_loop_count(1)
         self.check_aborted_count(0)
@@ -412,7 +411,7 @@
         res = self.meta_interp(f, [72])
         assert res == 6
         self.check_loop_count(2)     # the loop and the bridge
-        self.check_loops(new_with_vtable=2,  # loop: nothing; bridge: vref, xy
+        self.check_resops(new_with_vtable=2,  # loop: nothing; bridge: vref, xy
                          new_array=2)        # bridge: next4, next5
         self.check_aborted_count(0)
 
@@ -442,8 +441,8 @@
         #
         res = self.meta_interp(f, [15])
         assert res == 1
-        self.check_loops(new_with_vtable=2,     # vref, xy
-                         new_array=1)           # next1
+        self.check_resops(new_with_vtable=4,     # vref, xy
+                          new_array=2)           # next1
         self.check_aborted_count(0)
 
     def test_recursive_call_1(self):
@@ -543,7 +542,7 @@
         #
         res = self.meta_interp(f, [15])
         assert res == 1
-        self.check_loops(new_with_vtable=2)     # vref, xy
+        self.check_resops(new_with_vtable=4)     # vref, xy
 
     def test_cannot_use_invalid_virtualref(self):
         myjitdriver = JitDriver(greens = [], reds = ['n'])
diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py
--- a/pypy/jit/metainterp/test/test_warmspot.py
+++ b/pypy/jit/metainterp/test/test_warmspot.py
@@ -1,10 +1,7 @@
 import py
-from pypy.jit.metainterp.warmspot import ll_meta_interp
 from pypy.jit.metainterp.warmspot import get_stats
-from pypy.rlib.jit import JitDriver
-from pypy.rlib.jit import unroll_safe
+from pypy.rlib.jit import JitDriver, set_param, unroll_safe
 from pypy.jit.backend.llgraph import runner
-from pypy.jit.metainterp.history import BoxInt
 
 from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
 from pypy.jit.metainterp.optimizeopt import ALL_OPTS_NAMES
@@ -97,18 +94,18 @@
                 n = A().m(n)
             return n
         def f(n, enable_opts):
-            myjitdriver.set_param('enable_opts', hlstr(enable_opts))
+            set_param(None, 'enable_opts', hlstr(enable_opts))
             return g(n)
 
         # check that the set_param will override the default
         res = self.meta_interp(f, [10, llstr('')])
         assert res == 0
-        self.check_loops(new_with_vtable=1)
+        self.check_resops(new_with_vtable=1)
 
         res = self.meta_interp(f, [10, llstr(ALL_OPTS_NAMES)],
                                enable_opts='')
         assert res == 0
-        self.check_loops(new_with_vtable=0)
+        self.check_resops(new_with_vtable=0)
 
     def test_unwanted_loops(self):
         mydriver = JitDriver(reds = ['n', 'total', 'm'], greens = [])
@@ -163,7 +160,7 @@
             return n
         self.meta_interp(f, [50], backendopt=True)
         self.check_enter_count_at_most(2)
-        self.check_loops(call=0)
+        self.check_resops(call=0)
 
     def test_loop_header(self):
         # artificial test: we enter into the JIT only when can_enter_jit()
@@ -187,7 +184,7 @@
         assert f(15) == 1
         res = self.meta_interp(f, [15], backendopt=True)
         assert res == 1
-        self.check_loops(int_add=1)   # I get 13 without the loop_header()
+        self.check_resops(int_add=2)   # I get 13 without the loop_header()
 
     def test_omit_can_enter_jit(self):
         # Simple test comparing the effects of always giving a can_enter_jit(),
@@ -249,8 +246,8 @@
                 m = m - 1
         self.meta_interp(f1, [8])
         self.check_loop_count(1)
-        self.check_loops({'int_sub': 1, 'int_gt': 1, 'guard_true': 1,
-                          'jump': 1})
+        self.check_resops({'jump': 2, 'guard_true': 2, 'int_gt': 2,
+                           'int_sub': 2})
 
     def test_void_red_variable(self):
         mydriver = JitDriver(greens=[], reds=['a', 'm'])
diff --git a/pypy/jit/metainterp/test/test_ztranslation.py b/pypy/jit/metainterp/test/test_ztranslation.py
--- a/pypy/jit/metainterp/test/test_ztranslation.py
+++ b/pypy/jit/metainterp/test/test_ztranslation.py
@@ -1,7 +1,7 @@
 import py
 from pypy.jit.metainterp.warmspot import rpython_ll_meta_interp, ll_meta_interp
 from pypy.jit.backend.llgraph import runner
-from pypy.rlib.jit import JitDriver, unroll_parameters
+from pypy.rlib.jit import JitDriver, unroll_parameters, set_param
 from pypy.rlib.jit import PARAMETERS, dont_look_inside, hint
 from pypy.jit.metainterp.jitprof import Profiler
 from pypy.rpython.lltypesystem import lltype, llmemory
@@ -57,9 +57,9 @@
                               get_printable_location=get_printable_location)
         def f(i):
             for param, defl in unroll_parameters:
-                jitdriver.set_param(param, defl)
-            jitdriver.set_param("threshold", 3)
-            jitdriver.set_param("trace_eagerness", 2)
+                set_param(jitdriver, param, defl)
+            set_param(jitdriver, "threshold", 3)
+            set_param(jitdriver, "trace_eagerness", 2)
             total = 0
             frame = Frame(i)
             while frame.l[0] > 3:
@@ -117,8 +117,8 @@
                 raise ValueError
             return 2
         def main(i):
-            jitdriver.set_param("threshold", 3)
-            jitdriver.set_param("trace_eagerness", 2)
+            set_param(jitdriver, "threshold", 3)
+            set_param(jitdriver, "trace_eagerness", 2)
             total = 0
             n = i
             while n > 3:
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
@@ -120,7 +120,8 @@
                 op = block.operations[i]
                 if (op.opname == 'jit_marker' and
                     op.args[0].value == marker_name and
-                    op.args[1].value.active):   # the jitdriver
+                    (op.args[1].value is None or
+                    op.args[1].value.active)):   # the jitdriver
                     results.append((graph, block, i))
     return results
 
@@ -846,11 +847,18 @@
         _, PTR_SET_PARAM_STR_FUNCTYPE = self.cpu.ts.get_FuncType(
             [lltype.Ptr(STR)], lltype.Void)
         def make_closure(jd, fullfuncname, is_string):
-            state = jd.warmstate
-            def closure(i):
-                if is_string:
-                    i = hlstr(i)
-                getattr(state, fullfuncname)(i)
+            if jd is None:
+                def closure(i):
+                    if is_string:
+                        i = hlstr(i)
+                    for jd in self.jitdrivers_sd:
+                        getattr(jd.warmstate, fullfuncname)(i)
+            else:
+                state = jd.warmstate
+                def closure(i):
+                    if is_string:
+                        i = hlstr(i)
+                    getattr(state, fullfuncname)(i)
             if is_string:
                 TP = PTR_SET_PARAM_STR_FUNCTYPE
             else:
@@ -859,12 +867,16 @@
             return Constant(funcptr, TP)
         #
         for graph, block, i in find_set_param(graphs):
+            
             op = block.operations[i]
-            for jd in self.jitdrivers_sd:
-                if jd.jitdriver is op.args[1].value:
-                    break
+            if op.args[1].value is not None:
+                for jd in self.jitdrivers_sd:
+                    if jd.jitdriver is op.args[1].value:
+                        break
+                else:
+                    assert 0, "jitdriver of set_param() not found"
             else:
-                assert 0, "jitdriver of set_param() not found"
+                jd = None
             funcname = op.args[2].value
             key = jd, funcname
             if key not in closures:
diff --git a/pypy/jit/tl/spli/test/test_jit.py b/pypy/jit/tl/spli/test/test_jit.py
--- a/pypy/jit/tl/spli/test/test_jit.py
+++ b/pypy/jit/tl/spli/test/test_jit.py
@@ -36,7 +36,7 @@
                 i = i + 1
             return i
         self.interpret(f, [])
-        self.check_loops(new_with_vtable=0)
+        self.check_resops(new_with_vtable=0)
 
     def test_bridge(self):
         py.test.skip('We currently cant virtualize across bridges')
@@ -52,7 +52,7 @@
             return total
 
         self.interpret(f, [1, 10])
-        self.check_loops(new_with_vtable=0)
+        self.check_resops(new_with_vtable=0)
 
     def test_bridge_bad_case(self):
         py.test.skip('We currently cant virtualize across bridges')
@@ -67,7 +67,7 @@
             return a + b
 
         self.interpret(f, [1, 10])
-        self.check_loops(new_with_vtable=1) # XXX should eventually be 0?
+        self.check_resops(new_with_vtable=1) # XXX should eventually be 0?
         # I think it should be either 0 or 2, 1 makes little sense
         # If the loop after entering goes first time to the bridge, a
         # is rewrapped again, without preserving the identity. I'm not
diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py
--- a/pypy/module/__builtin__/functional.py
+++ b/pypy/module/__builtin__/functional.py
@@ -95,17 +95,17 @@
     return space.newlist(res_w)
 
 
-def range_withspecialized_implementation(space, start, step, howmany):
+def range_withspecialized_implementation(space, start, step, length):
     assert space.config.objspace.std.withrangelist
-    from pypy.objspace.std.rangeobject import W_RangeListObject
-    return W_RangeListObject(start, step, howmany)
+    from pypy.objspace.std.listobject import make_range_list
+    return make_range_list(space, start, step, length)
 
 bigint_one = rbigint.fromint(1)
 
 def range_with_longs(space, w_start, w_stop, w_step):
 
     start = lo = space.bigint_w(w_start)
-    stop  = hi = space.bigint_w(w_stop)
+    hi = space.bigint_w(w_stop)
     step  = st = space.bigint_w(w_step)
 
     if not step.tobool():
diff --git a/pypy/module/_weakref/test/test_weakref.py b/pypy/module/_weakref/test/test_weakref.py
--- a/pypy/module/_weakref/test/test_weakref.py
+++ b/pypy/module/_weakref/test/test_weakref.py
@@ -324,6 +324,7 @@
         class A(object): pass
         a = A()
         assert _weakref.proxy(a) is _weakref.proxy(a)
+        assert _weakref.proxy(a) is _weakref.proxy(a, None)
 
     def test_callable_proxy(self):
         import _weakref, gc
diff --git a/pypy/module/cpyext/listobject.py b/pypy/module/cpyext/listobject.py
--- a/pypy/module/cpyext/listobject.py
+++ b/pypy/module/cpyext/listobject.py
@@ -32,7 +32,7 @@
     Py_DecRef(space, w_item)
     if not isinstance(w_list, W_ListObject):
         PyErr_BadInternalCall(space)
-    wrappeditems = w_list.wrappeditems
+    wrappeditems = w_list.getitems()
     if index < 0 or index >= len(wrappeditems):
         raise OperationError(space.w_IndexError, space.wrap(
             "list assignment index out of range"))
@@ -47,7 +47,7 @@
     IndexError exception."""
     if not isinstance(w_list, W_ListObject):
         PyErr_BadInternalCall(space)
-    wrappeditems = w_list.wrappeditems
+    wrappeditems = w_list.getitems()
     if index < 0 or index >= len(wrappeditems):
         raise OperationError(space.w_IndexError, space.wrap(
             "list index out of range"))
@@ -74,7 +74,7 @@
     """Macro form of PyList_Size() without error checking.
     """
     assert isinstance(w_list, W_ListObject)
-    return len(w_list.wrappeditems)
+    return len(w_list.getitems())
 
 
 @cpython_api([PyObject], Py_ssize_t, error=-1)
diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py
--- a/pypy/module/cpyext/sequence.py
+++ b/pypy/module/cpyext/sequence.py
@@ -56,7 +56,7 @@
     PySequence_Fast(), o is not NULL, and that i is within bounds.
     """
     if isinstance(w_obj, listobject.W_ListObject):
-        w_res = w_obj.wrappeditems[index]
+        w_res = w_obj.getitem(index)
     else:
         assert isinstance(w_obj, tupleobject.W_TupleObject)
         w_res = w_obj.wrappeditems[index]
@@ -70,7 +70,7 @@
     PySequence_Fast_GET_SIZE() is faster because it can assume o is a list
     or tuple."""
     if isinstance(w_obj, listobject.W_ListObject):
-        return len(w_obj.wrappeditems)
+        return w_obj.length()
     assert isinstance(w_obj, tupleobject.W_TupleObject)
     return len(w_obj.wrappeditems)
 
diff --git a/pypy/module/gc/test/test_referents.py b/pypy/module/gc/test/test_referents.py
--- a/pypy/module/gc/test/test_referents.py
+++ b/pypy/module/gc/test/test_referents.py
@@ -7,9 +7,13 @@
         from pypy.rlib import rgc
         cls._backup = [rgc.get_rpy_roots]
         w = cls.space.wrap
+        space = cls.space
         class RandomRPythonObject(object):
             pass
-        cls.ALL_ROOTS = [w(4), w([2, 7]), RandomRPythonObject()]
+        l4 = space.newlist([w(4)])
+        l2 = space.newlist([w(2)])
+        l7 = space.newlist([w(7)])
+        cls.ALL_ROOTS = [l4, space.newlist([l2, l7]), RandomRPythonObject()]
         cls.w_ALL_ROOTS = cls.space.newlist(cls.ALL_ROOTS)
         rgc.get_rpy_roots = lambda: (
             map(rgc._GcRef, cls.ALL_ROOTS) + [rgc.NULL_GCREF]*17)
@@ -41,14 +45,14 @@
         if self.runappdirect:
             pass    # unsure what to test
         else:
-            assert lst[0] == 4
-            assert lst[1] == [2, 7]
+            assert lst[0] == [4]
+            assert lst[1] == [[2], [7]]
             assert type(lst[2]) is gc.GcRef
             assert len(lst) == 3
 
     def test_get_rpy_referents(self):
         import gc
-        y = 12345
+        y = [12345]
         x = [y]
         lst = gc.get_rpy_referents(x)
         # After translation, 'lst' should contain the RPython-level list
@@ -88,8 +92,8 @@
 
     def test_get_referents(self):
         import gc
-        y = 12345
-        z = 23456
+        y = [12345]
+        z = [23456]
         x = [y, z]
         lst = gc.get_referents(x)
         assert y in lst and z in lst
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -2,17 +2,19 @@
 
 
 class Module(MixedModule):
-    applevel_name = 'numpy'
+    applevel_name = 'numpypy'
 
     interpleveldefs = {
-        'array': 'interp_numarray.SingleDimArray',
+        'array': 'interp_numarray.NDimArray',
         'dtype': 'interp_dtype.W_Dtype',
         'ufunc': 'interp_ufuncs.W_Ufunc',
 
         'zeros': 'interp_numarray.zeros',
         'empty': 'interp_numarray.zeros',
         'ones': 'interp_numarray.ones',
+        'dot': 'interp_numarray.dot',
         'fromstring': 'interp_support.fromstring',
+        'flatiter': 'interp_numarray.W_FlatIterator',
 
         'True_': 'space.w_True',
         'False_': 'space.w_False',
@@ -48,6 +50,7 @@
         ("sign", "sign"),
         ("sin", "sin"),
         ("subtract", "subtract"),
+        ('sqrt', 'sqrt'),
         ("tan", "tan"),
     ]:
         interpleveldefs[exposed] = "interp_ufuncs.get(space).%s" % impl
@@ -57,4 +60,5 @@
         'mean': 'app_numpy.mean',
         'inf': 'app_numpy.inf',
         'e': 'app_numpy.e',
+        'arange': 'app_numpy.arange',
     }
diff --git a/pypy/module/micronumpy/app_numpy.py b/pypy/module/micronumpy/app_numpy.py
--- a/pypy/module/micronumpy/app_numpy.py
+++ b/pypy/module/micronumpy/app_numpy.py
@@ -1,17 +1,38 @@
 import math
 
-import numpy
+import numpypy
 
 
 inf = float("inf")
 e = math.e
 
+
 def average(a):
     # This implements a weighted average, for now we don't implement the
     # weighting, just the average part!
     return mean(a)
 
+
 def mean(a):
     if not hasattr(a, "mean"):
-        a = numpy.array(a)
+        a = numpypy.array(a)
     return a.mean()
+
+
+def arange(start, stop=None, step=1, dtype=None):
+    '''arange([start], stop[, step], dtype=None)
+    Generate values in the half-interval [start, stop).
+    '''
+    if stop is None:
+        stop = start
+        start = 0
+    if dtype is None:
+        test = numpypy.array([start, stop, step, 0])
+        dtype = test.dtype
+    arr = numpypy.zeros(int(math.ceil((stop - start) / step)), dtype=dtype)
+    i = start
+    for j in range(arr.size):
+        arr[j] = i
+        j += 1
+        i += step
+    return arr
diff --git a/pypy/module/micronumpy/bench/add.py b/pypy/module/micronumpy/bench/add.py
--- a/pypy/module/micronumpy/bench/add.py
+++ b/pypy/module/micronumpy/bench/add.py
@@ -1,5 +1,8 @@
 
-import numpy
+try:
+    import numpypy as numpy
+except:
+    import numpy
 
 def f():
     a = numpy.zeros(10000000)
diff --git a/pypy/module/micronumpy/bench/iterate.py b/pypy/module/micronumpy/bench/iterate.py
--- a/pypy/module/micronumpy/bench/iterate.py
+++ b/pypy/module/micronumpy/bench/iterate.py
@@ -1,5 +1,8 @@
 
-import numpy
+try:
+    import numpypy as numpy
+except:
+    import numpy
 
 def f():
     sum = 0
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -6,10 +6,10 @@
 from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root
 from pypy.module.micronumpy.interp_dtype import W_Float64Dtype, W_BoolDtype
 from pypy.module.micronumpy.interp_numarray import (Scalar, BaseArray,
-     descr_new_array, scalar_w, SingleDimArray)
+     descr_new_array, scalar_w, NDimArray)
 from pypy.module.micronumpy import interp_ufuncs
 from pypy.rlib.objectmodel import specialize
-
+import re
 
 class BogusBytecode(Exception):
     pass
@@ -23,11 +23,18 @@
 class WrongFunctionName(Exception):
     pass
 
+class TokenizerError(Exception):
+    pass
+
+class BadToken(Exception):
+    pass
+
 SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any", "unegative"]
 
 class FakeSpace(object):
     w_ValueError = None
     w_TypeError = None
+    w_IndexError = None
     w_None = None
 
     w_bool = "bool"
@@ -36,6 +43,7 @@
     w_list = "list"
     w_long = "long"
     w_tuple = 'tuple'
+    w_slice = "slice"
 
     def __init__(self):
         """NOT_RPYTHON"""
@@ -43,13 +51,26 @@
         self.w_float64dtype = W_Float64Dtype(self)
 
     def issequence_w(self, w_obj):
-        return isinstance(w_obj, ListObject) or isinstance(w_obj, SingleDimArray)
+        return isinstance(w_obj, ListObject) or isinstance(w_obj, NDimArray)
 
     def isinstance_w(self, w_obj, w_tp):
+        if w_obj.tp == w_tp:
+            return True
         return False
 
     def decode_index4(self, w_idx, size):
-        return (self.int_w(w_idx), 0, 0, 1)
+        if isinstance(w_idx, IntObject):
+            return (self.int_w(w_idx), 0, 0, 1)
+        else:
+            assert isinstance(w_idx, SliceObject)
+            start, stop, step = w_idx.start, w_idx.stop, w_idx.step
+            if step == 0:
+                return (0, size, 1, size)
+            if start < 0:
+                start += size
+            if stop < 0:
+                stop += size
+            return (start, stop, step, size//step)
 
     @specialize.argtype(1)
     def wrap(self, obj):
@@ -59,7 +80,9 @@
             return BoolObject(obj)
         elif isinstance(obj, int):
             return IntObject(obj)
-        raise Exception
+        elif isinstance(obj, W_Root):
+            return obj
+        raise NotImplementedError
 
     def newlist(self, items):
         return ListObject(items)
@@ -67,6 +90,7 @@
     def listview(self, obj):
         assert isinstance(obj, ListObject)
         return obj.items
+    fixedview = listview
 
     def float(self, w_obj):
         assert isinstance(w_obj, FloatObject)
@@ -107,6 +131,12 @@
         assert isinstance(what, tp)
         return what
 
+    def len_w(self, w_obj):
+        if isinstance(w_obj, ListObject):
+            return len(w_obj.items)
+        # XXX array probably
+        assert False
+
 class FloatObject(W_Root):
     tp = FakeSpace.w_float
     def __init__(self, floatval):
@@ -127,6 +157,13 @@
     def __init__(self, items):
         self.items = items
 
+class SliceObject(W_Root):
+    tp = FakeSpace.w_slice
+    def __init__(self, start, stop, step):
+        self.start = start
+        self.stop = stop
+        self.step = step
+
 class InterpreterState(object):
     def __init__(self, code):
         self.code = code
@@ -161,7 +198,7 @@
         interp.variables[self.name] = self.expr.execute(interp)
 
     def __repr__(self):
-        return "%% = %r" % (self.name, self.expr)
+        return "%r = %r" % (self.name, self.expr)
 
 class ArrayAssignment(Node):
     def __init__(self, name, index, expr):
@@ -171,8 +208,11 @@
 
     def execute(self, interp):
         arr = interp.variables[self.name]
-        w_index = self.index.execute(interp).eval(0).wrap(interp.space)
-        w_val = self.expr.execute(interp).eval(0).wrap(interp.space)
+        w_index = self.index.execute(interp).eval(arr.start_iter()).wrap(interp.space)
+        # cast to int
+        if isinstance(w_index, FloatObject):
+            w_index = IntObject(int(w_index.floatval))
+        w_val = self.expr.execute(interp).eval(arr.start_iter()).wrap(interp.space)
         arr.descr_setitem(interp.space, w_index, w_val)
 
     def __repr__(self):
@@ -180,7 +220,7 @@
 
 class Variable(Node):
     def __init__(self, name):
-        self.name = name
+        self.name = name.strip(" ")
 
     def execute(self, interp):
         return interp.variables[self.name]
@@ -196,11 +236,11 @@
 
     def execute(self, interp):
         w_lhs = self.lhs.execute(interp)
+        if isinstance(self.rhs, SliceConstant):
+            w_rhs = self.rhs.wrap(interp.space)
+        else:
+            w_rhs = self.rhs.execute(interp)
         assert isinstance(w_lhs, BaseArray)
-        if isinstance(self.rhs, SliceConstant):
-            # XXX interface has changed on multidim branch
-            raise NotImplementedError
-        w_rhs = self.rhs.execute(interp)
         if self.name == '+':
             w_res = w_lhs.descr_add(interp.space, w_rhs)
         elif self.name == '*':
@@ -209,12 +249,10 @@
             w_res = w_lhs.descr_sub(interp.space, w_rhs)            
         elif self.name == '->':
             if isinstance(w_rhs, Scalar):
-                index = int(interp.space.float_w(
-                    w_rhs.value.wrap(interp.space)))
-                dtype = interp.space.fromcache(W_Float64Dtype)
-                return Scalar(dtype, w_lhs.get_concrete().eval(index))
-            else:
-                raise NotImplementedError
+                w_rhs = w_rhs.eval(w_rhs.start_iter()).wrap(interp.space)
+                assert isinstance(w_rhs, FloatObject)
+                w_rhs = IntObject(int(w_rhs.floatval))
+            w_res = w_lhs.descr_getitem(interp.space, w_rhs)
         else:
             raise NotImplementedError
         if not isinstance(w_res, BaseArray):
@@ -248,7 +286,8 @@
         w_list = interp.space.newlist(
             [interp.space.wrap(float(i)) for i in range(self.v)])
         dtype = interp.space.fromcache(W_Float64Dtype)
-        return descr_new_array(interp.space, None, w_list, w_dtype=dtype)
+        return descr_new_array(interp.space, None, w_list, w_dtype=dtype,
+                               w_order=None)
 
     def __repr__(self):
         return 'Range(%s)' % self.v
@@ -270,17 +309,24 @@
     def execute(self, interp):
         w_list = self.wrap(interp.space)
         dtype = interp.space.fromcache(W_Float64Dtype)
-        return descr_new_array(interp.space, None, w_list, w_dtype=dtype)
+        return descr_new_array(interp.space, None, w_list, w_dtype=dtype,
+                               w_order=None)
 
     def __repr__(self):
         return "[" + ", ".join([repr(item) for item in self.items]) + "]"
 
 class SliceConstant(Node):
-    def __init__(self):
-        pass
+    def __init__(self, start, stop, step):
+        # no negative support for now
+        self.start = start
+        self.stop = stop
+        self.step = step
+
+    def wrap(self, space):
+        return SliceObject(self.start, self.stop, self.step)
 
     def __repr__(self):
-        return 'slice()'
+        return 'slice(%s,%s,%s)' % (self.start, self.stop, self.step)
 
 class Execute(Node):
     def __init__(self, expr):
@@ -294,7 +340,7 @@
 
 class FunctionCall(Node):
     def __init__(self, name, args):
-        self.name = name
+        self.name = name.strip(" ")
         self.args = args
 
     def __repr__(self):
@@ -337,95 +383,172 @@
         else:
             raise WrongFunctionName
 
+_REGEXES = [
+    ('-?[\d\.]+', 'number'),
+    ('\[', 'array_left'),
+    (':', 'colon'),
+    ('\w+', 'identifier'),
+    ('\]', 'array_right'),
+    ('(->)|[\+\-\*\/]', 'operator'),
+    ('=', 'assign'),
+    (',', 'coma'),
+    ('\|', 'pipe'),
+    ('\(', 'paren_left'),
+    ('\)', 'paren_right'),
+]
+REGEXES = []
+
+for r, name in _REGEXES:
+    REGEXES.append((re.compile(r' *(' + r + ')'), name))
+del _REGEXES
+
+class Token(object):
+    def __init__(self, name, v):
+        self.name = name
+        self.v = v
+
+    def __repr__(self):
+        return '(%s, %s)' % (self.name, self.v)
+
+empty = Token('', '')
+
+class TokenStack(object):
+    def __init__(self, tokens):
+        self.tokens = tokens
+        self.c = 0
+
+    def pop(self):
+        token = self.tokens[self.c]
+        self.c += 1
+        return token
+
+    def get(self, i):
+        if self.c + i >= len(self.tokens):
+            return empty
+        return self.tokens[self.c + i]
+
+    def remaining(self):
+        return len(self.tokens) - self.c
+
+    def push(self):
+        self.c -= 1
+
+    def __repr__(self):
+        return repr(self.tokens[self.c:])
+
 class Parser(object):
-    def parse_identifier(self, id):
-        id = id.strip(" ")
-        #assert id.isalpha()
-        return Variable(id)
+    def tokenize(self, line):
+        tokens = []
+        while True:
+            for r, name in REGEXES:
+                m = r.match(line)
+                if m is not None:
+                    g = m.group(0)
+                    tokens.append(Token(name, g))
+                    line = line[len(g):]
+                    if not line:
+                        return TokenStack(tokens)
+                    break
+            else:
+                raise TokenizerError(line)
 
-    def parse_expression(self, expr):
-        tokens = [i for i in expr.split(" ") if i]
-        if len(tokens) == 1:
-            return self.parse_constant_or_identifier(tokens[0])
+    def parse_number_or_slice(self, tokens):
+        start_tok = tokens.pop()
+        if start_tok.name == 'colon':
+            start = 0
+        else:
+            if tokens.get(0).name != 'colon':
+                return FloatConstant(start_tok.v)
+            start = int(start_tok.v)
+            tokens.pop()
+        if not tokens.get(0).name in ['colon', 'number']:
+            stop = -1
+            step = 1
+        else:
+            next = tokens.pop()
+            if next.name == 'colon':
+                stop = -1
+                step = int(tokens.pop().v)
+            else:
+                stop = int(next.v)
+                if tokens.get(0).name == 'colon':
+                    tokens.pop()
+                    step = int(tokens.pop().v)
+                else:
+                    step = 1
+        return SliceConstant(start, stop, step)
+            
+        
+    def parse_expression(self, tokens):
         stack = []
-        tokens.reverse()
-        while tokens:
+        while tokens.remaining():
             token = tokens.pop()
-            if token == ')':
-                raise NotImplementedError
-            elif self.is_identifier_or_const(token):
-                if stack:
-                    name = stack.pop().name
-                    lhs = stack.pop()
-                    rhs = self.parse_constant_or_identifier(token)
-                    stack.append(Operator(lhs, name, rhs))
+            if token.name == 'identifier':
+                if tokens.remaining() and tokens.get(0).name == 'paren_left':
+                    stack.append(self.parse_function_call(token.v, tokens))
                 else:
-                    stack.append(self.parse_constant_or_identifier(token))
+                    stack.append(Variable(token.v))
+            elif token.name == 'array_left':
+                stack.append(ArrayConstant(self.parse_array_const(tokens)))
+            elif token.name == 'operator':
+                stack.append(Variable(token.v))
+            elif token.name == 'number' or token.name == 'colon':
+                tokens.push()
+                stack.append(self.parse_number_or_slice(tokens))
+            elif token.name == 'pipe':
+                stack.append(RangeConstant(tokens.pop().v))
+                end = tokens.pop()
+                assert end.name == 'pipe'
             else:
-                stack.append(Variable(token))
-        assert len(stack) == 1
-        return stack[-1]
+                tokens.push()
+                break
+        stack.reverse()
+        lhs = stack.pop()
+        while stack:
+            op = stack.pop()
+            assert isinstance(op, Variable)
+            rhs = stack.pop()
+            lhs = Operator(lhs, op.name, rhs)
+        return lhs
 
-    def parse_constant(self, v):
-        lgt = len(v)-1
-        assert lgt >= 0
-        if ':' in v:
-            # a slice
-            assert v == ':'
-            return SliceConstant()
-        if v[0] == '[':
-            return ArrayConstant([self.parse_constant(elem)
-                                  for elem in v[1:lgt].split(",")])
-        if v[0] == '|':
-            return RangeConstant(v[1:lgt])
-        return FloatConstant(v)
-
-    def is_identifier_or_const(self, v):
-        c = v[0]
-        if ((c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z') or
-            (c >= '0' and c <= '9') or c in '-.[|:'):
-            if v == '-' or v == "->":
-                return False
-            return True
-        return False
-
-    def parse_function_call(self, v):
-        l = v.split('(')
-        assert len(l) == 2
-        name = l[0]
-        cut = len(l[1]) - 1
-        assert cut >= 0
-        args = [self.parse_constant_or_identifier(id)
-                for id in l[1][:cut].split(",")]
+    def parse_function_call(self, name, tokens):
+        args = []
+        tokens.pop() # lparen
+        while tokens.get(0).name != 'paren_right':
+            args.append(self.parse_expression(tokens))
         return FunctionCall(name, args)
 
-    def parse_constant_or_identifier(self, v):
-        c = v[0]
-        if (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z'):
-            if '(' in v:
-                return self.parse_function_call(v)
-            return self.parse_identifier(v)
-        return self.parse_constant(v)
-
-    def parse_array_subscript(self, v):
-        v = v.strip(" ")
-        l = v.split("[")
-        lgt = len(l[1]) - 1
-        assert lgt >= 0
-        rhs = self.parse_constant_or_identifier(l[1][:lgt])
-        return l[0], rhs
+    def parse_array_const(self, tokens):
+        elems = []
+        while True:
+            token = tokens.pop()
+            if token.name == 'number':
+                elems.append(FloatConstant(token.v))
+            elif token.name == 'array_left':
+                elems.append(ArrayConstant(self.parse_array_const(tokens)))
+            else:
+                raise BadToken()
+            token = tokens.pop()
+            if token.name == 'array_right':
+                return elems
+            assert token.name == 'coma'
         
-    def parse_statement(self, line):
-        if '=' in line:
-            lhs, rhs = line.split("=")
-            lhs = lhs.strip(" ")
-            if '[' in lhs:
-                name, index = self.parse_array_subscript(lhs)
-                return ArrayAssignment(name, index, self.parse_expression(rhs))
-            else: 
-                return Assignment(lhs, self.parse_expression(rhs))
-        else:
-            return Execute(self.parse_expression(line))
+    def parse_statement(self, tokens):
+        if (tokens.get(0).name == 'identifier' and
+            tokens.get(1).name == 'assign'):
+            lhs = tokens.pop().v
+            tokens.pop()
+            rhs = self.parse_expression(tokens)
+            return Assignment(lhs, rhs)
+        elif (tokens.get(0).name == 'identifier' and
+              tokens.get(1).name == 'array_left'):
+            name = tokens.pop().v
+            tokens.pop()
+            index = self.parse_expression(tokens)
+            tokens.pop()
+            tokens.pop()
+            return ArrayAssignment(name, index, self.parse_expression(tokens))
+        return Execute(self.parse_expression(tokens))
 
     def parse(self, code):
         statements = []
@@ -434,7 +557,8 @@
                 line = line.split('#', 1)[0]
             line = line.strip(" ")
             if line:
-                statements.append(self.parse_statement(line))
+                tokens = self.tokenize(line)
+                statements.append(self.parse_statement(tokens))
         return Code(statements)
 
 def numpy_compile(code):
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
@@ -221,6 +221,7 @@
 
     @binop
     def div(self, v1, v2):
+        # XXX this won't work after translation, probably requires ovfcheck
         try:
             return v1 / v2
         except ZeroDivisionError:
@@ -292,6 +293,12 @@
         if not -1.0 < v < 1.0:
             return rfloat.NAN
         return math.atanh(v)
+    @unaryop
+    def sqrt(self, v):
+        try:
+            return math.sqrt(v)
+        except ValueError:
+            return rfloat.NAN
 
 class IntegerArithmeticDtype(ArithmeticTypeMixin):
     _mixin_ = True
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -1,45 +1,369 @@
 from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.error import OperationError
-from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.error import OperationError, operationerrfmt
+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.rlib import jit
 from pypy.rpython.lltypesystem import lltype
 from pypy.tool.sourcetools import func_with_new_name
+from pypy.rlib.rstring import StringBuilder
+from pypy.rlib.objectmodel import instantiate
 
 
-numpy_driver = jit.JitDriver(greens = ['signature'],
-                             reds = ['result_size', 'i', 'self', 'result'])
-all_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self', 'dtype'])
-any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self', 'dtype'])
-slice_driver = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest'])
+numpy_driver = jit.JitDriver(
+    greens=['shapelen', 'signature'],
+    reds=['result_size', 'i', 'ri', 'self', 'result']
+)
+all_driver = jit.JitDriver(
+    greens=['shapelen', 'signature'],
+    reds=['i', 'self', 'dtype']
+)
+any_driver = jit.JitDriver(
+    greens=['shapelen', 'signature'],
+    reds=['i', 'self', 'dtype']
+)
+slice_driver = jit.JitDriver(
+    greens=['shapelen', 'signature'],
+    reds=['self', 'source', 'source_iter', 'res_iter']
+)
 
-def descr_new_array(space, w_subtype, w_size_or_iterable, w_dtype=None):
-    l = space.listview(w_size_or_iterable)
+def _find_shape_and_elems(space, w_iterable):
+    shape = [space.len_w(w_iterable)]
+    batch = space.listview(w_iterable)
+    while True:
+        new_batch = []
+        if not batch:
+            return shape, []
+        if not space.issequence_w(batch[0]):
+            for elem in batch:
+                if space.issequence_w(elem):
+                    raise OperationError(space.w_ValueError, space.wrap(
+                        "setting an array element with a sequence"))
+            return shape, batch
+        size = space.len_w(batch[0])
+        for w_elem in batch:
+            if not space.issequence_w(w_elem) or space.len_w(w_elem) != size:
+                raise OperationError(space.w_ValueError, space.wrap(
+                    "setting an array element with a sequence"))
+            new_batch += space.listview(w_elem)
+        shape.append(size)
+        batch = new_batch
+
+def shape_agreement(space, shape1, shape2):
+    ret = _shape_agreement(shape1, shape2)
+    if len(ret) < max(len(shape1), len(shape2)):
+        raise OperationError(space.w_ValueError,
+            space.wrap("operands could not be broadcast together with shapes (%s) (%s)" % (
+                ",".join([str(x) for x in shape1]),
+                ",".join([str(x) for x in shape2]),
+            ))
+        )
+    return ret
+
+def _shape_agreement(shape1, shape2):
+    """ Checks agreement about two shapes with respect to broadcasting. Returns
+    the resulting shape.
+    """
+    lshift = 0
+    rshift = 0
+    if len(shape1) > len(shape2):
+        m = len(shape1)
+        n = len(shape2)
+        rshift = len(shape2) - len(shape1)
+        remainder = shape1
+    else:
+        m = len(shape2)
+        n = len(shape1)
+        lshift = len(shape1) - len(shape2)
+        remainder = shape2
+    endshape = [0] * m
+    indices1 = [True] * m
+    indices2 = [True] * m
+    for i in range(m - 1, m - n - 1, -1):
+        left = shape1[i + lshift]
+        right = shape2[i + rshift]
+        if left == right:
+            endshape[i] = left
+        elif left == 1:
+            endshape[i] = right
+            indices1[i + lshift] = False
+        elif right == 1:
+            endshape[i] = left
+            indices2[i + rshift] = False
+        else:
+            return []
+            #raise OperationError(space.w_ValueError, space.wrap(
+            #    "frames are not aligned"))
+    for i in range(m - n):
+        endshape[i] = remainder[i]
+    return endshape
+
+def descr_new_array(space, w_subtype, w_item_or_iterable, w_dtype=None,
+                    w_order=NoneNotWrapped):
+    # find scalar
+    if not space.issequence_w(w_item_or_iterable):
+        w_dtype = interp_ufuncs.find_dtype_for_scalar(space,
+                                                      w_item_or_iterable,
+                                                      w_dtype)
+        dtype = space.interp_w(interp_dtype.W_Dtype,
+           space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype))
+        return scalar_w(space, dtype, w_item_or_iterable)
+    if w_order is None:
+        order = 'C'
+    else:
+        order = space.str_w(w_order)
+        if order != 'C':  # or order != 'F':
+            raise operationerrfmt(space.w_ValueError, "Unknown order: %s",
+                                  order)
+    shape, elems_w = _find_shape_and_elems(space, w_item_or_iterable)
+    # they come back in C order
+    size = len(elems_w)
     if space.is_w(w_dtype, space.w_None):
         w_dtype = None
-        for w_item in l:
-            w_dtype = interp_ufuncs.find_dtype_for_scalar(space, w_item, w_dtype)
+        for w_elem in elems_w:
+            w_dtype = interp_ufuncs.find_dtype_for_scalar(space, w_elem,
+                                                          w_dtype)
             if w_dtype is space.fromcache(interp_dtype.W_Float64Dtype):
                 break
-        if w_dtype is None:
-            w_dtype = space.w_None
-
+    if w_dtype is None:
+        w_dtype = space.w_None
     dtype = space.interp_w(interp_dtype.W_Dtype,
         space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
     )
-    arr = SingleDimArray(len(l), dtype=dtype)
-    i = 0
-    for w_elem in l:
-        dtype.setitem_w(space, arr.storage, i, w_elem)
-        i += 1
+    arr = NDimArray(size, shape[:], dtype=dtype, order=order)
+    shapelen = len(shape)
+    arr_iter = arr.start_iter(arr.shape)
+    for i in range(len(elems_w)):
+        w_elem = elems_w[i]
+        dtype.setitem_w(space, arr.storage, arr_iter.offset, w_elem)
+        arr_iter = arr_iter.next(shapelen)
     return arr
 
+# 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
+
+    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, size):
+        self.offset = start
+        self.step = step
+        self.size = size
+
+    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"]
+    _attrs_ = ["invalidates", "signature", "shape", "strides", "backstrides",
+               "start", 'order']
 
-    def __init__(self):
+    _immutable_fields_ = ['start', "order"]
+
+    strides = None
+    start = 0
+
+    def __init__(self, shape, order):
         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:
@@ -99,7 +423,7 @@
 
     def _reduce_ufunc_impl(ufunc_name):
         def impl(self, space):
-            return getattr(interp_ufuncs.get(space), ufunc_name).descr_reduce(space, self)
+            return getattr(interp_ufuncs.get(space), ufunc_name).reduce(space, self, multidim=True)
         return func_with_new_name(impl, "reduce_%s_impl" % ufunc_name)
 
     descr_sum = _reduce_ufunc_impl("add")
@@ -108,23 +432,30 @@
     descr_min = _reduce_ufunc_impl("minimum")
 
     def _reduce_argmax_argmin_impl(op_name):
-        reduce_driver = jit.JitDriver(greens=['signature'],
-                         reds = ['i', 'size', 'result', 'self', 'cur_best', 'dtype'])
-        def loop(self, size):
+        reduce_driver = jit.JitDriver(
+            greens=['shapelen', 'signature'],
+            reds=['result', 'idx', 'i', 'self', 'cur_best', 'dtype']
+        )
+        def loop(self):
+            i = self.start_iter()
+            cur_best = self.eval(i)
+            shapelen = len(self.shape)
+            i = i.next(shapelen)
+            dtype = self.find_dtype()
             result = 0
-            cur_best = self.eval(0)
-            i = 1
-            dtype = self.find_dtype()
-            while i < size:
+            idx = 1
+            while not i.done():
                 reduce_driver.jit_merge_point(signature=self.signature,
+                                              shapelen=shapelen,
                                               self=self, dtype=dtype,
-                                              size=size, i=i, result=result,
+                                              i=i, result=result, idx=idx,
                                               cur_best=cur_best)
                 new_best = getattr(dtype, op_name)(cur_best, self.eval(i))
                 if dtype.ne(new_best, cur_best):
-                    result = i
+                    result = idx
                     cur_best = new_best
-                i += 1
+                i = i.next(shapelen)
+                idx += 1
             return result
         def impl(self, space):
             size = self.find_size()
@@ -132,31 +463,35 @@
                 raise OperationError(space.w_ValueError,
                     space.wrap("Can't call %s on zero-size arrays" \
                             % op_name))
-            return space.wrap(loop(self, size))
+            return space.wrap(loop(self))
         return func_with_new_name(impl, "reduce_arg%s_impl" % op_name)
 
     def _all(self):
-        size = self.find_size()
         dtype = self.find_dtype()
-        i = 0
-        while i < size:
-            all_driver.jit_merge_point(signature=self.signature, self=self, dtype=dtype, size=size, i=i)
+        i = self.start_iter()
+        shapelen = len(self.shape)
+        while not i.done():
+            all_driver.jit_merge_point(signature=self.signature,
+                                       shapelen=shapelen, self=self,
+                                       dtype=dtype, i=i)
             if not dtype.bool(self.eval(i)):
                 return False
-            i += 1
+            i = i.next(shapelen)
         return True
     def descr_all(self, space):
         return space.wrap(self._all())
 
     def _any(self):
-        size = self.find_size()
         dtype = self.find_dtype()
-        i = 0
-        while i < size:
-            any_driver.jit_merge_point(signature=self.signature, self=self, size=size, dtype=dtype, i=i)
+        i = self.start_iter()
+        shapelen = len(self.shape)
+        while not i.done():
+            any_driver.jit_merge_point(signature=self.signature,
+                                       shapelen=shapelen, self=self,
+                                       dtype=dtype, i=i)
             if dtype.bool(self.eval(i)):
                 return True
-            i += 1
+            i = i.next(shapelen)
         return False
     def descr_any(self, space):
         return space.wrap(self._any())
@@ -173,25 +508,6 @@
             assert isinstance(w_res, BaseArray)
             return w_res.descr_sum(space)
 
-    def _getnums(self, comma):
-        dtype = self.find_dtype()
-        if self.find_size() > 1000:
-            nums = [
-                dtype.str_format(self.eval(index))
-                for index in range(3)
-            ]
-            nums.append("..." + "," * comma)
-            nums.extend([
-                dtype.str_format(self.eval(index))
-                for index in range(self.find_size() - 3, self.find_size())
-            ])
-        else:
-            nums = [
-                dtype.str_format(self.eval(index))
-                for index in range(self.find_size())
-            ]
-        return nums
-
     def get_concrete(self):
         raise NotImplementedError
 
@@ -199,7 +515,7 @@
         return space.wrap(self.find_dtype())
 
     def descr_get_shape(self, space):
-        return space.newtuple([self.descr_len(space)])
+        return space.newtuple([space.wrap(i) for i in self.shape])
 
     def descr_get_size(self, space):
         return space.wrap(self.find_size())
@@ -211,89 +527,290 @@
         return self.get_concrete().descr_len(space)
 
     def descr_repr(self, space):
-        # Simple implementation so that we can see the array. Needs work.
+        res = StringBuilder()
+        res.append("array(")
         concrete = self.get_concrete()
-        res = "array([" + ", ".join(concrete._getnums(False)) + "]"
         dtype = concrete.find_dtype()
+        if not concrete.find_size():
+            res.append('[]')
+            if len(self.shape) > 1:
+                # An empty slice reports its shape
+                res.append(", shape=(")
+                self_shape = str(self.shape)
+                res.append_slice(str(self_shape), 1, len(self_shape) - 1)
+                res.append(')')
+        else:
+            concrete.to_str(space, 1, res, indent='       ')
         if (dtype is not space.fromcache(interp_dtype.W_Float64Dtype) and
-            dtype is not space.fromcache(interp_dtype.W_Int64Dtype)) or not self.find_size():
-            res += ", dtype=" + dtype.name
-        res += ")"
-        return space.wrap(res)
+            dtype is not space.fromcache(interp_dtype.W_Int64Dtype)) or \
+            not self.find_size():
+            res.append(", dtype=" + dtype.name)
+        res.append(")")
+        return space.wrap(res.build())
+
+    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()
+        if size < 1:
+            builder.append('[]')
+            return
+        if size > 1000:
+            # Once this goes True it does not go back to False for recursive
+            # calls
+            use_ellipsis = True
+        dtype = self.find_dtype()
+        ndims = len(self.shape)
+        i = 0
+        start = True
+        builder.append('[')
+        if ndims > 1:
+            if use_ellipsis:
+                for i in range(3):
+                    if start:
+                        start = False
+                    else:
+                        builder.append(',' * comma + '\n')
+                        if ndims == 3:
+                            builder.append('\n' + indent)
+                        else:
+                            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.to_str(space, comma, builder, indent=indent + ' ', use_ellipsis=use_ellipsis)
+                builder.append('\n' + indent + '..., ')
+                i = self.shape[0] - 3
+            while i < self.shape[0]:
+                if start:
+                    start = False
+                else:
+                    builder.append(',' * comma + '\n')
+                    if ndims == 3:
+                        builder.append('\n' + indent)
+                    else:
+                        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.to_str(space, comma, builder, indent=indent + ' ', use_ellipsis=use_ellipsis)
+                i += 1
+        elif ndims == 1:
+            spacer = ',' * comma + ' '
+            item = self.start
+            # An iterator would be a nicer way to walk along the 1d array, but
+            # how do I reset it if printing ellipsis? iterators have no
+            # "set_offset()"
+            i = 0
+            if use_ellipsis:
+                for i in range(3):
+                    if start:
+                        start = False
+                    else:
+                        builder.append(spacer)
+                    builder.append(dtype.str_format(self.getitem(item)))
+                    item += self.strides[0]
+                # Add a comma only if comma is False - this prevents adding two
+                # commas
+                builder.append(spacer + '...' + ',' * (1 - comma))
+                # Ugly, but can this be done with an iterator?
+                item = self.start + self.backstrides[0] - 2 * self.strides[0]
+                i = self.shape[0] - 3
+            while i < self.shape[0]:
+                if start:
+                    start = False
+                else:
+                    builder.append(spacer)
+                builder.append(dtype.str_format(self.getitem(item)))
+                item += self.strides[0]
+                i += 1
+        else:
+            builder.append('[')
+        builder.append(']')
 
     def descr_str(self, space):
-        # Simple implementation so that we can see the array. Needs work.
+        ret = StringBuilder()
         concrete = self.get_concrete()
-        return space.wrap("[" + " ".join(concrete._getnums(True)) + "]")
+        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):
+            idx = space.int_w(w_idx)
+            if not self.shape:
+                if idx != 0:
+                    raise OperationError(space.w_IndexError,
+                                         space.wrap("index out of range"))
+                return 0
+            if idx < 0:
+                idx = self.shape[0] + idx
+            if idx < 0 or idx >= self.shape[0]:
+                raise OperationError(space.w_IndexError,
+                                     space.wrap("index out of range"))
+            return self.start + idx * self.strides[0]
+        index = [space.int_w(w_item)
+                 for w_item in space.fixedview(w_idx)]
+        item = self.start
+        for i in range(len(index)):
+            v = index[i]
+            if v < 0:
+                v += self.shape[i]
+            if v < 0 or v >= self.shape[i]:
+                raise operationerrfmt(space.w_IndexError,
+                    "index (%d) out of range (0<=index<%d", i, self.shape[i],
+                )
+            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))]
 
     def descr_getitem(self, space, w_idx):
-        # TODO: indexing by arrays and lists
-        if space.isinstance_w(w_idx, space.w_tuple):
-            length = space.len_w(w_idx)
-            if length == 0:
-                return space.wrap(self)
-            if length > 1: # only one dimension for now.
-                raise OperationError(space.w_IndexError,
-                                     space.wrap("invalid index"))
-            w_idx = space.getitem(w_idx, space.wrap(0))
-        start, stop, step, slice_length = space.decode_index4(w_idx, self.find_size())
-        if step == 0:
-            # Single index
-            return self.get_concrete().eval(start).wrap(space)
-        else:
-            # Slice
-            new_sig = signature.Signature.find_sig([
-                SingleDimSlice.signature, self.signature
-            ])
-            res = SingleDimSlice(start, stop, step, slice_length, self, new_sig)
-            return space.wrap(res)
+        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).wrap(space)
+        chunks = self._prepare_slice_args(space, w_idx)
+        return space.wrap(self.create_slice(space, chunks))
 
     def descr_setitem(self, space, w_idx, w_value):
-        # TODO: indexing by arrays and lists
         self.invalidated()
-        if space.isinstance_w(w_idx, space.w_tuple):
-            length = space.len_w(w_idx)
-            if length > 1: # only one dimension for now.
-                raise OperationError(space.w_IndexError,
-                                     space.wrap("invalid index"))
-            if length == 0:
-                w_idx = space.newslice(space.wrap(0),
-                                      space.wrap(self.find_size()),
-                                      space.wrap(1))
+        concrete = self.get_concrete()
+        if self._single_item_result(space, w_idx):
+            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)
+            concrete.setitem_w(space, item, w_value)
+            return
+        if isinstance(w_value, BaseArray):
+            # for now we just copy if setting part of an array from
+            # part of itself. can be improved.
+            if (concrete.get_root_storage() ==
+                w_value.get_concrete().get_root_storage()):
+                w_value = space.call_function(space.gettypefor(BaseArray), w_value)
+                assert isinstance(w_value, BaseArray)
+        else:
+            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:
-                w_idx = space.getitem(w_idx, space.wrap(0))
-        start, stop, step, slice_length = space.decode_index4(w_idx,
-                                                              self.find_size())
-        if step == 0:
-            # Single index
-            self.get_concrete().setitem_w(space, start, w_value)
+                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:
-            concrete = self.get_concrete()
-            if isinstance(w_value, BaseArray):
-                # for now we just copy if setting part of an array from
-                # part of itself. can be improved.
-                if (concrete.get_root_storage() ==
-                    w_value.get_concrete().get_root_storage()):
-                    w_value = space.call_function(space.gettypefor(BaseArray), w_value)
-                    assert isinstance(w_value, BaseArray)
-            else:
-                w_value = convert_to_array(space, w_value)
-            concrete.setslice(space, start, stop, step,
-                                               slice_length, w_value)
+            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([
+            NDimSlice.signature, self.signature,
+        ])
+        return NDimSlice(self, new_sig, start, strides[:], backstrides[:],
+                         shape[:])
 
     def descr_mean(self, space):
-        return space.wrap(space.float_w(self.descr_sum(space))/self.find_size())
+        return space.wrap(space.float_w(self.descr_sum(space)) / self.find_size())
 
-    def _sliceloop(self, start, stop, step, source, dest):
-        i = start
-        j = 0
-        while (step > 0 and i < stop) or (step < 0 and i > stop):
-            slice_driver.jit_merge_point(signature=source.signature, step=step,
-                                         stop=stop, i=i, j=j, source=source,
-                                         dest=dest)
-            dest.setitem(i, source.eval(j).convert_to(dest.find_dtype()))
-            j += 1
-            i += step
+    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)).wrap(space)))
+
+    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([
+            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(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 convert_to_array(space, w_obj):
     if isinstance(w_obj, BaseArray):
@@ -309,36 +826,50 @@
         return scalar_w(space, dtype, w_obj)
 
 def scalar_w(space, dtype, w_obj):
+    assert isinstance(dtype, interp_dtype.W_Dtype)
     return Scalar(dtype, dtype.unwrap(space, w_obj))
 
 class Scalar(BaseArray):
     """
-    Intermediate class representing a float literal.
+    Intermediate class representing a literal.
     """
     signature = signature.BaseSignature()
 
-    _attrs_ = ["dtype", "value"]
+    _attrs_ = ["dtype", "value", "shape"]
 
     def __init__(self, dtype, value):
-        BaseArray.__init__(self)
+        BaseArray.__init__(self, [], 'C')
         self.dtype = dtype
         self.value = value
 
     def find_size(self):
-        raise ValueError
+        return 1
+
+    def get_concrete(self):
+        return self
 
     def find_dtype(self):
         return self.dtype
 
-    def eval(self, i):
+    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.str_format(self.value))
+
+
 class VirtualArray(BaseArray):
     """
     Class for representing virtual arrays, such as binary ops or ufuncs
     """
-    def __init__(self, signature, res_dtype):
-        BaseArray.__init__(self)
+    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
@@ -351,13 +882,18 @@
         i = 0
         signature = self.signature
         result_size = self.find_size()
-        result = SingleDimArray(result_size, self.find_dtype())
-        while i < result_size:
+        result = 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,
-                                         result_size=result_size, i=i,
+                                         shapelen=shapelen,
+                                         result_size=result_size, i=i, ri=ri,
                                          self=self, result=result)
-            result.dtype.setitem(result.storage, i, self.eval(i))
-            i += 1
+            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):
@@ -369,10 +905,13 @@
         self.force_if_needed()
         return self.forced_result
 
-    def eval(self, i):
+    def eval(self, iter):
         if self.forced_result is not None:
-            return self.forced_result.eval(i)
-        return self._eval(i)
+            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)
@@ -388,8 +927,9 @@
 
 
 class Call1(VirtualArray):
-    def __init__(self, signature, res_dtype, values):
-        VirtualArray.__init__(self, signature, res_dtype)
+    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):
@@ -401,40 +941,53 @@
     def _find_dtype(self):
         return self.res_dtype
 
-    def _eval(self, i):
-        val = self.values.eval(i).convert_to(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))
+
 class Call2(VirtualArray):
     """
     Intermediate class for performing binary operations.
     """
-    def __init__(self, signature, calc_dtype, res_dtype, left, right):
-        VirtualArray.__init__(self, signature, res_dtype)
+    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):
-        try:
-            return self.left.find_size()
-        except ValueError:
-            pass
-        return self.right.find_size()
+        return self.size
 
-    def _eval(self, i):
-        lhs = self.left.eval(i).convert_to(self.calc_dtype)
-        rhs = self.right.eval(i).convert_to(self.calc_dtype)
+    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]
@@ -446,8 +999,10 @@
     Class for representing views of arrays, they will reflect changes of parent
     arrays. Example: slices
     """
-    def __init__(self, parent, signature):
-        BaseArray.__init__(self)
+    def __init__(self, parent, signature, strides, backstrides, shape):
+        self.strides = strides
+        self.backstrides = backstrides
+        BaseArray.__init__(self, shape, parent.order)
         self.signature = signature
         self.parent = parent
         self.invalidates = parent.invalidates
@@ -459,39 +1014,41 @@
         self.parent.get_concrete()
         return self
 
-    def eval(self, i):
-        return self.parent.eval(self.calc_index(i))
+    def getitem(self, item):
+        return self.parent.getitem(item)
+
+    def eval(self, iter):
+        return self.parent.getitem(iter.get_offset())
 
     @unwrap_spec(item=int)
     def setitem_w(self, space, item, w_value):
-        return self.parent.setitem_w(space, self.calc_index(item), w_value)
+        return self.parent.setitem_w(space, item, w_value)
 
     def setitem(self, item, value):
         # This is currently not possible to be called from anywhere.
         raise NotImplementedError
 
     def descr_len(self, space):
-        return space.wrap(self.find_size())
+        if self.shape:
+            return space.wrap(self.shape[0])
+        return space.wrap(1)
 
-    def calc_index(self, item):
-        raise NotImplementedError
 
-class SingleDimSlice(ViewArray):
+class VirtualView(VirtualArray):
+    pass
+
+class NDimSlice(ViewArray):
     signature = signature.BaseSignature()
 
-    def __init__(self, start, stop, step, slice_length, parent, signature):
-        ViewArray.__init__(self, parent, signature)
-        if isinstance(parent, SingleDimSlice):
-            self.start = parent.calc_index(start)
-            self.stop = parent.calc_index(stop)
-            self.step = parent.step * step
-            self.parent = parent.parent
-        else:
-            self.start = start
-            self.stop = stop
-            self.step = step
-            self.parent = parent
-        self.size = slice_length
+    def __init__(self, parent, signature, start, strides, backstrides,
+                 shape):
+        if isinstance(parent, 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 get_root_storage(self):
         return self.parent.get_concrete().get_root_storage()
@@ -502,20 +1059,41 @@
     def find_dtype(self):
         return self.parent.find_dtype()
 
-    def setslice(self, space, start, stop, step, slice_length, arr):
-        start = self.calc_index(start)
-        if stop != -1:
-            stop = self.calc_index(stop)
-        step = self.step * step
-        self._sliceloop(start, stop, step, arr, self.parent)
+    def setslice(self, space, w_value):
+        res_shape = shape_agreement(space, self.shape, w_value.shape)
+        self._sliceloop(w_value, res_shape)
 
-    def calc_index(self, item):
-        return (self.start + item * self.step)
+    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)
+        # XXX there is a possible optimization here with SingleDimViewIterator
+        #     ignore for now
+        return ViewIterator(self)
 
-class SingleDimArray(BaseArray):
-    def __init__(self, size, dtype):
-        BaseArray.__init__(self)
+    def setitem(self, item, value):
+        self.parent.setitem(item, value)
+
+class NDimArray(BaseArray):
+    """ 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)
@@ -533,11 +1111,17 @@
     def find_dtype(self):
         return self.dtype
 
-    def eval(self, i):
-        return self.dtype.getitem(self.storage, i)
+    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 descr_len(self, space):
-        return space.wrap(self.size)
+        if len(self.shape):
+            return space.wrap(self.shape[0])
+        raise OperationError(space.w_TypeError, space.wrap(
+            "len() of unsized object"))
 
     def setitem_w(self, space, item, w_value):
         self.invalidated()
@@ -547,30 +1131,52 @@
         self.invalidated()
         self.dtype.setitem(self.storage, item, value)
 
-    def setslice(self, space, start, stop, step, slice_length, arr):
-        self._sliceloop(start, stop, step, arr, self)
+    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 __del__(self):
         lltype.free(self.storage, flavor='raw', track_allocation=False)
 
- at unwrap_spec(size=int)
-def zeros(space, size, w_dtype=None):
+def _find_size_and_shape(space, w_size):
+    if space.isinstance_w(w_size, space.w_int):
+        size = space.int_w(w_size)
+        shape = [size]
+    else:
+        size = 1
+        shape = []
+        for w_item in space.fixedview(w_size):
+            item = space.int_w(w_item)
+            size *= item
+            shape.append(item)
+    return size, shape
+
+def zeros(space, w_size, w_dtype=None):
     dtype = space.interp_w(interp_dtype.W_Dtype,
         space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
     )
-    return space.wrap(SingleDimArray(size, dtype=dtype))
+    size, shape = _find_size_and_shape(space, w_size)
+    return space.wrap(NDimArray(size, shape[:], dtype=dtype))
 
- at unwrap_spec(size=int)
-def ones(space, size, w_dtype=None):
+def ones(space, w_size, w_dtype=None):
     dtype = space.interp_w(interp_dtype.W_Dtype,
         space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
     )
-
-    arr = SingleDimArray(size, dtype=dtype)
+    size, shape = _find_size_and_shape(space, w_size)
+    arr = NDimArray(size, shape[:], dtype=dtype)
     one = dtype.adapt_val(1)
     arr.dtype.fill(arr.storage, one, 0, size)
     return space.wrap(arr)
 
+def dot(space, w_obj, w_obj2):
+    w_arr = convert_to_array(space, w_obj)
+    if isinstance(w_arr, Scalar):
+        return convert_to_array(space, w_obj2).descr_dot(space, w_arr)
+    return w_arr.descr_dot(space, w_obj2)
+
 BaseArray.typedef = TypeDef(
     'numarray',
     __new__ = interp2app(descr_new_array),
@@ -583,6 +1189,7 @@
     __pos__ = interp2app(BaseArray.descr_pos),
     __neg__ = interp2app(BaseArray.descr_neg),
     __abs__ = interp2app(BaseArray.descr_abs),
+    __nonzero__ = interp2app(BaseArray.descr_nonzero),
 
     __add__ = interp2app(BaseArray.descr_add),
     __sub__ = interp2app(BaseArray.descr_sub),
@@ -612,6 +1219,9 @@
     shape = GetSetProperty(BaseArray.descr_get_shape),
     size = GetSetProperty(BaseArray.descr_get_size),
 
+    T = GetSetProperty(BaseArray.descr_get_transpose),
+    flat = GetSetProperty(BaseArray.descr_get_flatiter),
+
     mean = interp2app(BaseArray.descr_mean),
     sum = interp2app(BaseArray.descr_sum),
     prod = interp2app(BaseArray.descr_prod),
@@ -625,3 +1235,51 @@
 
     copy = interp2app(BaseArray.descr_copy),
 )
+
+
+class W_FlatIterator(ViewArray):
+    signature = signature.BaseSignature()
+    
+    @jit.unroll_safe
+    def __init__(self, arr):
+        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.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]
+
+    def descr_next(self, space):
+        if self.iter.done():
+            raise OperationError(space.w_StopIteration, space.wrap(''))
+        result = self.eval(self.iter)
+        self.iter = self.iter.next(self.shapelen)
+        return result.wrap(space)
+
+    def descr_iter(self):
+        return self
+
+
+W_FlatIterator.typedef = TypeDef(
+    'flatiter',
+    next = interp2app(W_FlatIterator.descr_next),
+    __iter__ = interp2app(W_FlatIterator.descr_iter),
+)
+W_FlatIterator.acceptable_as_base_class = False
diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py
--- a/pypy/module/micronumpy/interp_support.py
+++ b/pypy/module/micronumpy/interp_support.py
@@ -9,7 +9,7 @@
 
 @unwrap_spec(s=str)
 def fromstring(space, s):
-    from pypy.module.micronumpy.interp_numarray import SingleDimArray
+    from pypy.module.micronumpy.interp_numarray import NDimArray
     length = len(s)
 
     if length % FLOAT_SIZE == 0:
@@ -19,7 +19,7 @@
             "string length %d not divisable by %d" % (length, FLOAT_SIZE)))
 
     dtype = space.fromcache(W_Float64Dtype)
-    a = SingleDimArray(number, dtype=dtype)
+    a = NDimArray(number, [number], dtype=dtype)
 
     start = 0
     end = FLOAT_SIZE
@@ -31,4 +31,4 @@
         start += FLOAT_SIZE
         end += FLOAT_SIZE
 
-    return space.wrap(a)
\ No newline at end of file
+    return space.wrap(a)
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
@@ -1,6 +1,6 @@
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
 from pypy.module.micronumpy import interp_dtype, signature
 from pypy.rlib import jit
@@ -9,8 +9,8 @@
 
 
 reduce_driver = jit.JitDriver(
-    greens = ["signature"],
-    reds = ["i", "size", "self", "dtype", "value", "obj"]
+    greens = ['shapelen', "signature"],
+    reds = ["i", "self", "dtype", "value", "obj"]
 )
 
 class W_Ufunc(Wrappable):
@@ -45,8 +45,10 @@
         return self.call(space, __args__.arguments_w)
 
     def descr_reduce(self, space, w_obj):
+        return self.reduce(space, w_obj, multidim=False)
+
+    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"))
@@ -62,28 +64,33 @@
             space, obj.find_dtype(),
             promote_to_largest=True
         )
-        start = 0
+        start = obj.start_iter(obj.shape)
+        shapelen = len(obj.shape)
+        if shapelen > 1 and not multidim:
+            raise OperationError(space.w_NotImplementedError,
+                space.wrap("not implemented yet"))
         if self.identity is None:
             if size == 0:
                 raise operationerrfmt(space.w_ValueError, "zero-size array to "
                     "%s.reduce without identity", self.name)
-            value = obj.eval(0).convert_to(dtype)
-            start += 1
+            value = obj.eval(start).convert_to(dtype)
+            start = start.next(shapelen)
         else:
             value = self.identity.convert_to(dtype)
         new_sig = signature.Signature.find_sig([
             self.reduce_signature, obj.signature
         ])
-        return self.reduce(new_sig, start, value, obj, dtype, size).wrap(space)
+        return self.reduce_loop(new_sig, shapelen, start, value, obj,
+                           dtype).wrap(space)
 
-    def reduce(self, signature, start, value, obj, dtype, size):
-        i = start
-        while i < size:
-            reduce_driver.jit_merge_point(signature=signature, self=self,
+    def reduce_loop(self, signature, shapelen, i, value, obj, dtype):
+        while not i.done():
+            reduce_driver.jit_merge_point(signature=signature,
+                                          shapelen=shapelen, self=self,
                                           value=value, obj=obj, i=i,
-                                          dtype=dtype, size=size)
+                                          dtype=dtype)
             value = self.func(dtype, value, obj.eval(i).convert_to(dtype))
-            i += 1
+            i = i.next(shapelen)
         return value
 
 class W_Ufunc1(W_Ufunc):
@@ -111,7 +118,7 @@
             return self.func(res_dtype, w_obj.value.convert_to(res_dtype)).wrap(space)
 
         new_sig = signature.Signature.find_sig([self.signature, w_obj.signature])
-        w_res = Call1(new_sig, res_dtype, w_obj)
+        w_res = Call1(new_sig, w_obj.shape, res_dtype, w_obj, w_obj.order)
         w_obj.add_invalidates(w_res)
         return w_res
 
@@ -130,7 +137,7 @@
 
     def call(self, space, args_w):
         from pypy.module.micronumpy.interp_numarray import (Call2,
-            convert_to_array, Scalar)
+            convert_to_array, Scalar, shape_agreement)
 
         [w_lhs, w_rhs] = args_w
         w_lhs = convert_to_array(space, w_lhs)
@@ -153,7 +160,9 @@
         new_sig = signature.Signature.find_sig([
             self.signature, w_lhs.signature, w_rhs.signature
         ])
-        w_res = Call2(new_sig, calc_dtype, res_dtype, w_lhs, w_rhs)
+        new_shape = shape_agreement(space, w_lhs.shape, w_rhs.shape)
+        w_res = Call2(new_sig, new_shape, calc_dtype,
+                      res_dtype, w_lhs, w_rhs)
         w_lhs.add_invalidates(w_res)
         w_rhs.add_invalidates(w_res)
         return w_res
@@ -310,6 +319,8 @@
             ("floor", "floor", 1, {"promote_to_float": True}),
             ("exp", "exp", 1, {"promote_to_float": True}),
 
+            ('sqrt', 'sqrt', 1, {'promote_to_float': True}),
+
             ("sin", "sin", 1, {"promote_to_float": True}),
             ("cos", "cos", 1, {"promote_to_float": True}),
             ("tan", "tan", 1, {"promote_to_float": True}),
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
@@ -49,4 +49,4 @@
     _immutable_fields_ = ["func"]
 
     def __init__(self, func):
-        self.func = func
\ No newline at end of file
+        self.func = func
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
@@ -1,6 +1,6 @@
 from pypy.conftest import gettestobjspace
 from pypy.module.micronumpy import interp_dtype
-from pypy.module.micronumpy.interp_numarray import SingleDimArray, Scalar
+from pypy.module.micronumpy.interp_numarray import NDimArray, Scalar
 from pypy.module.micronumpy.interp_ufuncs import (find_binop_result_dtype,
         find_unaryop_result_dtype)
 
@@ -13,7 +13,7 @@
     def test_binop_signature(self, space):
         float64_dtype = space.fromcache(interp_dtype.W_Float64Dtype)
 
-        ar = SingleDimArray(10, dtype=float64_dtype)
+        ar = 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
@@ -22,7 +22,7 @@
         v4 = ar.descr_add(space, ar)
         assert v1.signature is v4.signature
 
-        bool_ar = SingleDimArray(10, dtype=space.fromcache(interp_dtype.W_BoolDtype))
+        bool_ar = NDimArray(10, [10], dtype=space.fromcache(interp_dtype.W_BoolDtype))
         v5 = ar.descr_add(space, bool_ar)
         assert v5.signature is not v1.signature
         assert v5.signature is not v2.signature
@@ -30,13 +30,13 @@
         assert v5.signature is v6.signature
 
     def test_slice_signature(self, space):
-        ar = SingleDimArray(10, dtype=space.fromcache(interp_dtype.W_Float64Dtype))
-        v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1)))
+        ar = NDimArray(10, [10], dtype=space.fromcache(interp_dtype.W_Float64Dtype))
+        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
 
-        v3 = ar.descr_add(space, v1)
-        v4 = ar.descr_add(space, v2)
+        v3 = v2.descr_add(space, v1)
+        v4 = v1.descr_add(space, v2)
         assert v3.signature is v4.signature
 
 class TestUfuncCoerscion(object):
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
@@ -5,7 +5,7 @@
 class TestCompiler(object):
     def compile(self, code):
         return numpy_compile(code)
-    
+
     def test_vars(self):
         code = """
         a = 2
@@ -25,7 +25,7 @@
         st = interp.code.statements[0]
         assert st.expr.items == [FloatConstant(1), FloatConstant(2),
                                  FloatConstant(3)]
-    
+
     def test_array_literal2(self):
         code = "a = [[1],[2],[3]]"
         interp = self.compile(code)
@@ -102,10 +102,11 @@
         code = """
         a = [1,2,3,4]
         b = [4,5,6,5]
-        a + b
+        c = a + b
+        c -> 3
         """
         interp = self.run(code)
-        assert interp.results[0]._getnums(False) == ["5.0", "7.0", "9.0", "9.0"]
+        assert interp.results[-1].value.val == 9
 
     def test_array_getitem(self):
         code = """
@@ -115,7 +116,7 @@
         """
         interp = self.run(code)
         assert interp.results[0].value.val == 3 + 6
-        
+
     def test_range_getitem(self):
         code = """
         r = |20| + 3
@@ -161,10 +162,32 @@
         assert interp.results[0].value.val == 256
 
     def test_slice(self):
-        py.test.skip("in progress")
         interp = self.run("""
         a = [1,2,3,4]
         b = a -> :
         b -> 3
         """)
-        assert interp.results[0].value.val == 3
+        assert interp.results[0].value.val == 4
+
+    def test_slice_step(self):
+        interp = self.run("""
+        a = |30|
+        b = a -> ::2
+        b -> 3
+        """)
+        assert interp.results[0].value.val == 6
+
+    def test_multidim_getitem(self):
+        interp = self.run("""
+        a = [[1,2]]
+        a -> 0 -> 1
+        """)
+        assert interp.results[0].value.val == 2
+
+    def test_multidim_getitem_2(self):
+        interp = self.run("""
+        a = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
+        b = a + a
+        b -> 1 -> 1
+        """)
+        assert interp.results[0].value.val == 8
diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py
--- a/pypy/module/micronumpy/test/test_dtypes.py
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -3,7 +3,7 @@
 
 class AppTestDtypes(BaseNumpyAppTest):
     def test_dtype(self):
-        from numpy import dtype
+        from numpypy import dtype
 
         d = dtype('?')
         assert d.num == 0
@@ -14,7 +14,7 @@
         raises(TypeError, dtype, 1042)
 
     def test_dtype_with_types(self):
-        from numpy import dtype
+        from numpypy import dtype
 
         assert dtype(bool).num == 0
         assert dtype(int).num == 7
@@ -22,13 +22,13 @@
         assert dtype(float).num == 12
 
     def test_array_dtype_attr(self):
-        from numpy import array, dtype
+        from numpypy import array, dtype
 
         a = array(range(5), long)
         assert a.dtype is dtype(long)
 
     def test_repr_str(self):
-        from numpy import dtype
+        from numpypy import dtype
 
         assert repr(dtype) == "<type 'numpy.dtype'>"
         d = dtype('?')
@@ -36,57 +36,57 @@
         assert str(d) == "bool"
 
     def test_bool_array(self):
-        import numpy
+        from numpypy import array, False_, True_
 
-        a = numpy.array([0, 1, 2, 2.5], dtype='?')
-        assert a[0] is numpy.False_
+        a = array([0, 1, 2, 2.5], dtype='?')
+        assert a[0] is False_
         for i in xrange(1, 4):
-            assert a[i] is numpy.True_
+            assert a[i] is True_
 
     def test_copy_array_with_dtype(self):
-        import numpy
+        from numpypy import array, False_, True_
 
-        a = numpy.array([0, 1, 2, 3], dtype=long)
+        a = array([0, 1, 2, 3], dtype=long)
         # int on 64-bit, long in 32-bit
         assert isinstance(a[0], (int, long))
         b = a.copy()
         assert isinstance(b[0], (int, long))
 
-        a = numpy.array([0, 1, 2, 3], dtype=bool)
-        assert a[0] is numpy.False_
+        a = array([0, 1, 2, 3], dtype=bool)
+        assert a[0] is False_
         b = a.copy()
-        assert b[0] is numpy.False_
+        assert b[0] is False_
 
     def test_zeros_bool(self):
-        import numpy
+        from numpypy import zeros, False_
 
-        a = numpy.zeros(10, dtype=bool)
+        a = zeros(10, dtype=bool)
         for i in range(10):
-            assert a[i] is numpy.False_
+            assert a[i] is False_
 
     def test_ones_bool(self):
-        import numpy
+        from numpypy import ones, True_
 
-        a = numpy.ones(10, dtype=bool)
+        a = ones(10, dtype=bool)
         for i in range(10):
-            assert a[i] is numpy.True_
+            assert a[i] is True_
 
     def test_zeros_long(self):
-        from numpy import zeros
+        from numpypy import zeros
         a = zeros(10, dtype=long)
         for i in range(10):
             assert isinstance(a[i], (int, long))
             assert a[1] == 0
 
     def test_ones_long(self):
-        from numpy import ones
+        from numpypy import ones
         a = ones(10, dtype=long)
         for i in range(10):
             assert isinstance(a[i], (int, long))
             assert a[1] == 1
 
     def test_overflow(self):
-        from numpy import array, dtype
+        from numpypy import array, dtype
         assert array([128], 'b')[0] == -128
         assert array([256], 'B')[0] == 0
         assert array([32768], 'h')[0] == -32768
@@ -98,7 +98,7 @@
         raises(OverflowError, "array([2**64], 'Q')")
 
     def test_bool_binop_types(self):
-        from numpy import array, dtype
+        from numpypy import array, dtype
         types = [
             '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd'
         ]
@@ -107,7 +107,7 @@
             assert (a + array([0], t)).dtype is dtype(t)
 
     def test_binop_types(self):
-        from numpy import array, dtype
+        from numpypy import array, dtype
         tests = [('b','B','h'), ('b','h','h'), ('b','H','i'), ('b','i','i'),
                  ('b','l','l'), ('b','q','q'), ('b','Q','d'), ('B','h','h'),
                  ('B','H','H'), ('B','i','i'), ('B','I','I'), ('B','l','l'),
@@ -129,7 +129,7 @@
             assert (array([1], d1) + array([1], d2)).dtype is dtype(dout)
 
     def test_add_int8(self):
-        from numpy import array, dtype
+        from numpypy import array, dtype
 
         a = array(range(5), dtype="int8")
         b = a + a
@@ -138,7 +138,7 @@
             assert b[i] == i * 2
 
     def test_add_int16(self):
-        from numpy import array, dtype
+        from numpypy import array, dtype
 
         a = array(range(5), dtype="int16")
         b = a + a
@@ -147,7 +147,7 @@
             assert b[i] == i * 2
 
     def test_add_uint32(self):
-        from numpy import array, dtype
+        from numpypy import array, dtype
 
         a = array(range(5), dtype="I")
         b = a + a
@@ -156,12 +156,12 @@
             assert b[i] == i * 2
 
     def test_shape(self):
-        from numpy import dtype
+        from numpypy import dtype
 
         assert dtype(long).shape == ()
 
     def test_cant_subclass(self):
-        from numpy import dtype
+        from numpypy import dtype
 
         # You can't subclass dtype
         raises(TypeError, type, "Foo", (dtype,), {})
diff --git a/pypy/module/micronumpy/test/test_module.py b/pypy/module/micronumpy/test/test_module.py
--- a/pypy/module/micronumpy/test/test_module.py
+++ b/pypy/module/micronumpy/test/test_module.py
@@ -3,19 +3,19 @@
 
 class AppTestNumPyModule(BaseNumpyAppTest):
     def test_mean(self):
-        from numpy import array, mean
+        from numpypy import array, mean
         assert mean(array(range(5))) == 2.0
         assert mean(range(5)) == 2.0
 
     def test_average(self):
-        from numpy import array, average
+        from numpypy import array, average
         assert average(range(10)) == 4.5
         assert average(array(range(10))) == 4.5
 
     def test_constants(self):
         import math
-        from numpy import inf, e
+        from numpypy import inf, e
         assert type(inf) is float
         assert inf == float("inf")
         assert e == math.e
-        assert type(e) is float
\ No newline at end of file
+        assert type(e) is float
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
@@ -1,15 +1,172 @@
+
+import py
 from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+from pypy.module.micronumpy.interp_numarray import NDimArray, shape_agreement
+from pypy.module.micronumpy import signature
+from pypy.interpreter.error import OperationError
 from pypy.conftest import gettestobjspace
 
 
+class MockDtype(object):
+    signature = signature.BaseSignature()
+
+    def malloc(self, size):
+        return None
+
+
+class TestNumArrayDirect(object):
+    def newslice(self, *args):
+        return self.space.newslice(*[self.space.wrap(arg) for arg in args])
+
+    def newtuple(self, *args):
+        args_w = []
+        for arg in args:
+            if isinstance(arg, int):
+                args_w.append(self.space.wrap(arg))
+            else:
+                args_w.append(arg)
+        return self.space.newtuple(args_w)
+
+    def test_strides_f(self):
+        a = NDimArray(100, [10, 5, 3], MockDtype(), 'F')
+        assert a.strides == [1, 10, 50]
+        assert a.backstrides == [9, 40, 100]
+
+    def test_strides_c(self):
+        a = NDimArray(100, [10, 5, 3], MockDtype(), 'C')
+        assert a.strides == [15, 3, 1]
+        assert a.backstrides == [135, 12, 2]
+
+    def test_create_slice_f(self):
+        space = self.space
+        a = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
+        s = a.create_slice(space, [(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)])
+        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)])
+        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)])
+        assert s.start == 20
+        assert s.shape == [10, 3]
+
+    def test_create_slice_c(self):
+        space = self.space
+        a = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'C')
+        s = a.create_slice(space, [(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)])
+        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)])
+        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)])
+        assert s.start == 6
+        assert s.shape == [10, 3]
+
+    def test_slice_of_slice_f(self):
+        space = self.space
+        a = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
+        s = a.create_slice(space, [(5, 0, 0, 1)])
+        assert s.start == 5
+        s2 = s.create_slice(space, [(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)])
+        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 = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), order='C')
+        s = a.create_slice(space, [(5, 0, 0, 1)])
+        assert s.start == 15 * 5
+        s2 = s.create_slice(space, [(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)])
+        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 = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), 'F')
+        s = a.create_slice(space, [(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 = NDimArray(10 * 5 * 3, [10, 5, 3], MockDtype(), order='C')
+        s = a.create_slice(space, [(9, -1, -2, 5)])
+        assert s.start == 135
+        assert s.strides == [-30, 3, 1]
+        assert s.backstrides == [-120, 12, 2]
+
+    def test_index_of_single_item_f(self):
+        a = 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)])
+        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))
+        assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 1))
+
+    def test_index_of_single_item_c(self):
+        a = 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)])
+        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))
+        assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 1))
+
+    def test_shape_agreement(self):
+        assert shape_agreement(self.space, [3], [3]) == [3]
+        assert shape_agreement(self.space, [1, 2, 3], [1, 2, 3]) == [1, 2, 3]
+        py.test.raises(OperationError, shape_agreement, self.space, [2], [3])
+        assert shape_agreement(self.space, [4, 4], []) == [4, 4]
+        assert shape_agreement(self.space,
+                [8, 1, 6, 1], [7, 1, 5]) == [8, 7, 6, 5]
+        assert shape_agreement(self.space,
+                [5, 2], [4, 3, 5, 2]) == [4, 3, 5, 2]
+
+
 class AppTestNumArray(BaseNumpyAppTest):
     def test_type(self):
-        from numpy import array
+        from numpypy import array
         ar = array(range(5))
         assert type(ar) is type(ar + ar)
 
     def test_init(self):
-        from numpy import zeros
+        from numpypy import zeros
         a = zeros(15)
         # Check that storage was actually zero'd.
         assert a[10] == 0.0
@@ -18,7 +175,7 @@
         assert a[13] == 5.3
 
     def test_size(self):
-        from numpy import array
+        from numpypy import array
         # XXX fixed on multidim branch
         #assert array(3).size == 1
         a = array([1, 2, 3])
@@ -30,13 +187,13 @@
         Test that empty() works.
         """
 
-        from numpy import empty
+        from numpypy import empty
         a = empty(2)
         a[1] = 1.0
         assert a[1] == 1.0
 
     def test_ones(self):
-        from numpy import ones
+        from numpypy import ones
         a = ones(3)
         assert len(a) == 3
         assert a[0] == 1
@@ -45,71 +202,21 @@
         assert a[2] == 4
 
     def test_copy(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = a.copy()
         for i in xrange(5):
             assert b[i] == a[i]
+        a[3] = 22
+        assert b[3] == 3
 
     def test_iterator_init(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         assert a[3] == 3
 
-    def test_repr(self):
-        from numpy import array, zeros
-        a = array(range(5), float)
-        assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])"
-        a = array([], float)
-        assert repr(a) == "array([], dtype=float64)"
-        a = zeros(1001)
-        assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])"
-        a = array(range(5), long)
-        assert repr(a) == "array([0, 1, 2, 3, 4])"
-        a = array([], long)
-        assert repr(a) == "array([], dtype=int64)"
-        a = array([True, False, True, False], "?")
-        assert repr(a) == "array([True, False, True, False], dtype=bool)"
-
-    def test_repr_slice(self):
-        from numpy import array, zeros
-        a = array(range(5), float)
-        b = a[1::2]
-        assert repr(b) == "array([1.0, 3.0])"
-        a = zeros(2002)
-        b = a[::2]
-        assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])"
-
-    def test_str(self):
-        from numpy import array, zeros
-        a = array(range(5), float)
-        assert str(a) == "[0.0 1.0 2.0 3.0 4.0]"
-        assert str((2*a)[:]) == "[0.0 2.0 4.0 6.0 8.0]"
-        a = zeros(1001)
-        assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]"
-
-        a = array(range(5), dtype=long)
-        assert str(a) == "[0 1 2 3 4]"
-        a = array([True, False, True, False], dtype="?")
-        assert str(a) == "[True False True False]"
-
-        a = array(range(5), dtype="int8")
-        assert str(a) == "[0 1 2 3 4]"
-
-        a = array(range(5), dtype="int16")
-        assert str(a) == "[0 1 2 3 4]"
-
-    def test_str_slice(self):
-        from numpy import array, zeros
-        a = array(range(5), float)
-        b = a[1::2]
-        assert str(b) == "[1.0 3.0]"
-        a = zeros(2002)
-        b = a[::2]
-        assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]"
-
     def test_getitem(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         raises(IndexError, "a[5]")
         a = a + a
@@ -118,7 +225,7 @@
         raises(IndexError, "a[-6]")
 
     def test_getitem_tuple(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         raises(IndexError, "a[(1,2)]")
         for i in xrange(5):
@@ -128,7 +235,7 @@
             assert a[i] == b[i]
 
     def test_setitem(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         a[-1] = 5.0
         assert a[4] == 5.0
@@ -136,18 +243,18 @@
         raises(IndexError, "a[-6] = 3.0")
 
     def test_setitem_tuple(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         raises(IndexError, "a[(1,2)] = [0,1]")
         for i in xrange(5):
-            a[(i,)] = i+1
-            assert a[i] == i+1
+            a[(i,)] = i + 1
+            assert a[i] == i + 1
         a[()] = range(5)
         for i in xrange(5):
             assert a[i] == i
 
     def test_setslice_array(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = array(range(2))
         a[1:4:2] = b
@@ -158,7 +265,7 @@
         assert b[1] == 0.
 
     def test_setslice_of_slice_array(self):
-        from numpy import array, zeros
+        from numpypy import array, zeros
         a = zeros(5)
         a[::2] = array([9., 10., 11.])
         assert a[0] == 9.
@@ -171,13 +278,13 @@
         assert a[3] == 1.
         assert a[4] == 11.
         a = zeros(10)
-        a[::2][::-1][::2] = array(range(1,4))
+        a[::2][::-1][::2] = array(range(1, 4))
         assert a[8] == 1.
         assert a[4] == 2.
         assert a[0] == 3.
 
     def test_setslice_list(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5), float)
         b = [0., 1.]
         a[1:4:2] = b
@@ -185,20 +292,28 @@
         assert a[3] == 1.
 
     def test_setslice_constant(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5), float)
         a[1:4:2] = 0.
         assert a[1] == 0.
         assert a[3] == 0.
 
+    def test_scalar(self):
+        from numpypy import array
+        a = array(3)
+        #assert a[0] == 3
+        raises(IndexError, "a[0]")
+        assert a.size == 1
+        assert a.shape == ()
+
     def test_len(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         assert len(a) == 5
         assert len(a + a) == 5
 
     def test_shape(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         assert a.shape == (5,)
         b = a + a
@@ -207,7 +322,7 @@
         assert c.shape == (3,)
 
     def test_add(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = a + a
         for i in range(5):
@@ -220,28 +335,28 @@
             assert c[i] == bool(a[i] + b[i])
 
     def test_add_other(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
-        b = array(range(4, -1, -1))
+        b = array([i for i in reversed(range(5))])
         c = a + b
         for i in range(5):
             assert c[i] == 4
 
     def test_add_constant(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = a + 5
         for i in range(5):
             assert b[i] == i + 5
 
     def test_radd(self):
-        from numpy import array
+        from numpypy import array
         r = 3 + array(range(3))
         for i in range(3):
             assert r[i] == i + 3
 
     def test_add_list(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = list(reversed(range(5)))
         c = a + b
@@ -250,14 +365,14 @@
             assert c[i] == 4
 
     def test_subtract(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = a - a
         for i in range(5):
             assert b[i] == 0
 
     def test_subtract_other(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = array([1, 1, 1, 1, 1])
         c = a - b
@@ -265,29 +380,29 @@
             assert c[i] == i - 1
 
     def test_subtract_constant(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = a - 5
         for i in range(5):
             assert b[i] == i - 5
 
     def test_mul(self):
-        import numpy
+        import numpypy
 
-        a = numpy.array(range(5))
+        a = numpypy.array(range(5))
         b = a * a
         for i in range(5):
             assert b[i] == i * i
 
-        a = numpy.array(range(5), dtype=bool)
+        a = numpypy.array(range(5), dtype=bool)
         b = a * a
-        assert b.dtype is numpy.dtype(bool)
-        assert b[0] is numpy.False_
+        assert b.dtype is numpypy.dtype(bool)
+        assert b[0] is numpypy.False_
         for i in range(1, 5):
-            assert b[i] is numpy.True_
+            assert b[i] is numpypy.True_
 
     def test_mul_constant(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = a * 5
         for i in range(5):
@@ -295,7 +410,7 @@
 
     def test_div(self):
         from math import isnan
-        from numpy import array, dtype, inf
+        from numpypy import array, dtype, inf
 
         a = array(range(1, 6))
         b = a / a
@@ -327,7 +442,7 @@
         assert c[2] == -inf
 
     def test_div_other(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = array([2, 2, 2, 2, 2], float)
         c = a / b
@@ -335,22 +450,22 @@
             assert c[i] == i / 2.0
 
     def test_div_constant(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = a / 5.0
         for i in range(5):
             assert b[i] == i / 5.0
 
     def test_pow(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5), float)
         b = a ** a
         for i in range(5):
-            print b[i], i**i
-            assert b[i] == i**i
+            print b[i], i ** i
+            assert b[i] == i ** i
 
     def test_pow_other(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5), float)
         b = array([2, 2, 2, 2, 2])
         c = a ** b
@@ -358,15 +473,15 @@
             assert c[i] == i ** 2
 
     def test_pow_constant(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5), float)
         b = a ** 2
         for i in range(5):
             assert b[i] == i ** 2
 
     def test_mod(self):
-        from numpy import array
-        a = array(range(1,6))
+        from numpypy import array
+        a = array(range(1, 6))
         b = a % a
         for i in range(5):
             assert b[i] == 0
@@ -378,7 +493,7 @@
             assert b[i] == 1
 
     def test_mod_other(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = array([2, 2, 2, 2, 2])
         c = a % b
@@ -386,15 +501,15 @@
             assert c[i] == i % 2
 
     def test_mod_constant(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = a % 2
         for i in range(5):
             assert b[i] == i % 2
 
     def test_pos(self):
-        from numpy import array
-        a = array([1.,-2.,3.,-4.,-5.])
+        from numpypy import array
+        a = array([1., -2., 3., -4., -5.])
         b = +a
         for i in range(5):
             assert b[i] == a[i]
@@ -404,8 +519,8 @@
             assert a[i] == i
 
     def test_neg(self):
-        from numpy import array
-        a = array([1.,-2.,3.,-4.,-5.])
+        from numpypy import array
+        a = array([1., -2., 3., -4., -5.])
         b = -a
         for i in range(5):
             assert b[i] == -a[i]
@@ -415,8 +530,8 @@
             assert a[i] == -i
 
     def test_abs(self):
-        from numpy import array
-        a = array([1.,-2.,3.,-4.,-5.])
+        from numpypy import array
+        a = array([1., -2., 3., -4., -5.])
         b = abs(a)
         for i in range(5):
             assert b[i] == abs(a[i])
@@ -426,7 +541,7 @@
             assert a[i + 5] == abs(i)
 
     def test_auto_force(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = a - 1
         a[2] = 3
@@ -440,12 +555,12 @@
         assert c[1] == 4
 
     def test_getslice(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         s = a[1:5]
         assert len(s) == 4
         for i in range(4):
-            assert s[i] == a[i+1]
+            assert s[i] == a[i + 1]
 
         s = (a + a)[1:2]
         assert len(s) == 1
@@ -454,15 +569,15 @@
         assert s[0] == 5
 
     def test_getslice_step(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(10))
         s = a[1:9:2]
         assert len(s) == 4
         for i in range(4):
-            assert s[i] == a[2*i+1]
+            assert s[i] == a[2 * i + 1]
 
     def test_slice_update(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         s = a[0:3]
         s[1] = 10
@@ -470,13 +585,12 @@
         a[2] = 20
         assert s[2] == 20
 
-
     def test_slice_invaidate(self):
         # check that slice shares invalidation list with
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         s = a[0:2]
-        b = array([10,11])
+        b = array([10, 11])
         c = s + b
         a[0] = 100
         assert c[0] == 10
@@ -487,13 +601,13 @@
         assert d[1] == 12
 
     def test_mean(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         assert a.mean() == 2.0
         assert a[:4].mean() == 1.5
 
     def test_sum(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         assert a.sum() == 10.0
         assert a[:4].sum() == 6.0
@@ -502,49 +616,60 @@
         assert a.sum() == 5
 
     def test_prod(self):
-        from numpy import array
-        a = array(range(1,6))
+        from numpypy import array
+        a = array(range(1, 6))
         assert a.prod() == 120.0
         assert a[:4].prod() == 24.0
 
     def test_max(self):
-        from numpy import array
+        from numpypy import array
         a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
         assert a.max() == 5.7
         b = array([])
         raises(ValueError, "b.max()")
 
     def test_max_add(self):
-        from numpy import array
+        from numpypy import array
         a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
-        assert (a+a).max() == 11.4
+        assert (a + a).max() == 11.4
 
     def test_min(self):
-        from numpy import array
+        from numpypy import array
         a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
         assert a.min() == -3.0
         b = array([])
         raises(ValueError, "b.min()")
 
     def test_argmax(self):
-        from numpy import array
+        from numpypy import array
         a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
-        assert a.argmax() == 2
+        r = a.argmax()
+        assert r == 2
         b = array([])
-        raises(ValueError, "b.argmax()")
+        raises(ValueError, b.argmax)
 
         a = array(range(-5, 5))
-        assert a.argmax() == 9
+        r = a.argmax()
+        assert r == 9
+        b = a[::2]
+        r = b.argmax()
+        assert r == 4
+        r = (a + a).argmax()
+        assert r == 9
+        a = array([1, 0, 0])
+        assert a.argmax() == 0
+        a = array([0, 0, 1])
+        assert a.argmax() == 2
 
     def test_argmin(self):
-        from numpy import array
+        from numpypy import array
         a = array([-1.2, 3.4, 5.7, -3.0, 2.7])
         assert a.argmin() == 3
         b = array([])
         raises(ValueError, "b.argmin()")
 
     def test_all(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         assert a.all() == False
         a[0] = 3.0
@@ -553,7 +678,7 @@
         assert b.all() == True
 
     def test_any(self):
-        from numpy import array, zeros
+        from numpypy import array, zeros
         a = array(range(5))
         assert a.any() == True
         b = zeros(5)
@@ -562,22 +687,24 @@
         assert c.any() == False
 
     def test_dot(self):
-        from numpy import array
+        from numpypy import array, dot
         a = array(range(5))
         assert a.dot(a) == 30.0
 
         a = array(range(5))
         assert a.dot(range(5)) == 30
+        assert dot(range(5), range(5)) == 30
+        assert (dot(5, [1, 2, 3]) == [5, 10, 15]).all()
 
     def test_dot_constant(self):
-        from numpy import array
+        from numpypy import array
         a = array(range(5))
         b = a.dot(2.5)
         for i in xrange(5):
             assert b[i] == 2.5 * a[i]
 
     def test_dtype_guessing(self):
-        from numpy import array, dtype
+        from numpypy import array, dtype
 
         assert array([True]).dtype is dtype(bool)
         assert array([True, False]).dtype is dtype(bool)
@@ -590,7 +717,7 @@
 
     def test_comparison(self):
         import operator
-        from numpy import array, dtype
+        from numpypy import array, dtype
 
         a = array(range(5))
         b = array(range(5), float)
@@ -608,6 +735,245 @@
             for i in xrange(5):
                 assert c[i] == func(b[i], 3)
 
+    def test_nonzero(self):
+        from numpypy import array
+        a = array([1, 2])
+        raises(ValueError, bool, a)
+        raises(ValueError, bool, a == a)
+        assert bool(array(1))
+        assert not bool(array(0))
+        assert bool(array([1]))
+        assert not bool(array([0]))
+
+
+class AppTestMultiDim(BaseNumpyAppTest):
+    def test_init(self):
+        import numpypy
+        a = numpypy.zeros((2, 2))
+        assert len(a) == 2
+
+    def test_shape(self):
+        import numpypy
+        assert numpypy.zeros(1).shape == (1,)
+        assert numpypy.zeros((2, 2)).shape == (2, 2)
+        assert numpypy.zeros((3, 1, 2)).shape == (3, 1, 2)
+        assert numpypy.array([[1], [2], [3]]).shape == (3, 1)
+        assert len(numpypy.zeros((3, 1, 2))) == 3
+        raises(TypeError, len, numpypy.zeros(()))
+        raises(ValueError, numpypy.array, [[1, 2], 3])
+
+    def test_getsetitem(self):
+        import numpypy
+        a = numpypy.zeros((2, 3, 1))
+        raises(IndexError, a.__getitem__, (2, 0, 0))
+        raises(IndexError, a.__getitem__, (0, 3, 0))
+        raises(IndexError, a.__getitem__, (0, 0, 1))
+        assert a[1, 1, 0] == 0
+        a[1, 2, 0] = 3
+        assert a[1, 2, 0] == 3
+        assert a[1, 1, 0] == 0
+        assert a[1, -1, 0] == 3
+
+    def test_slices(self):
+        import numpypy
+        a = numpypy.zeros((4, 3, 2))
+        raises(IndexError, a.__getitem__, (4,))
+        raises(IndexError, a.__getitem__, (3, 3))
+        raises(IndexError, a.__getitem__, (slice(None), 3))
+        a[0, 1, 1] = 13
+        a[1, 2, 1] = 15
+        b = a[0]
+        assert len(b) == 3
+        assert b.shape == (3, 2)
+        assert b[1, 1] == 13
+        b = a[1]
+        assert b.shape == (3, 2)
+        assert b[2, 1] == 15
+        b = a[:, 1]
+        assert b.shape == (4, 2)
+        assert b[0, 1] == 13
+        b = a[:, 1, :]
+        assert b.shape == (4, 2)
+        assert b[0, 1] == 13
+        b = a[1, 2]
+        assert b[1] == 15
+        b = a[:]
+        assert b.shape == (4, 3, 2)
+        assert b[1, 2, 1] == 15
+        assert b[0, 1, 1] == 13
+        b = a[:][:, 1][:]
+        assert b[2, 1] == 0.0
+        assert b[0, 1] == 13
+        raises(IndexError, b.__getitem__, (4, 1))
+        assert a[0][1][1] == 13
+        assert a[1][2][1] == 15
+
+    def test_init_2(self):
+        import numpypy
+        raises(ValueError, numpypy.array, [[1], 2])
+        raises(ValueError, numpypy.array, [[1, 2], [3]])
+        raises(ValueError, numpypy.array, [[[1, 2], [3, 4], 5]])
+        raises(ValueError, numpypy.array, [[[1, 2], [3, 4], [5]]])
+        a = numpypy.array([[1, 2], [4, 5]])
+        assert a[0, 1] == 2
+        assert a[0][1] == 2
+        a = numpypy.array(([[[1, 2], [3, 4], [5, 6]]]))
+        assert (a[0, 1] == [3, 4]).all()
+
+    def test_setitem_slice(self):
+        import numpypy
+        a = numpypy.zeros((3, 4))
+        a[1] = [1, 2, 3, 4]
+        assert a[1, 2] == 3
+        raises(TypeError, a[1].__setitem__, [1, 2, 3])
+        a = numpypy.array([[1, 2], [3, 4]])
+        assert (a == [[1, 2], [3, 4]]).all()
+        a[1] = numpypy.array([5, 6])
+        assert (a == [[1, 2], [5, 6]]).all()
+        a[:, 1] = numpypy.array([8, 10])
+        assert (a == [[1, 8], [5, 10]]).all()
+        a[0, :: -1] = numpypy.array([11, 12])
+        assert (a == [[12, 11], [5, 10]]).all()
+
+    def test_ufunc(self):
+        from numpypy import array
+        a = array([[1, 2], [3, 4], [5, 6]])
+        assert ((a + a) == \
+            array([[1 + 1, 2 + 2], [3 + 3, 4 + 4], [5 + 5, 6 + 6]])).all()
+
+    def test_getitem_add(self):
+        from numpypy import array
+        a = array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])
+        assert (a + a)[1, 1] == 8
+
+    def test_ufunc_negative(self):
+        from numpypy import array, negative
+        a = array([[1, 2], [3, 4]])
+        b = negative(a + a)
+        assert (b == [[-2, -4], [-6, -8]]).all()
+
+    def test_getitem_3(self):
+        from numpypy import array
+        a = array([[1, 2], [3, 4], [5, 6], [7, 8],
+                   [9, 10], [11, 12], [13, 14]])
+        b = a[::2]
+        print a
+        print b
+        assert (b == [[1, 2], [5, 6], [9, 10], [13, 14]]).all()
+        c = b + b
+        assert c[1][1] == 12
+
+    def test_multidim_ones(self):
+        from numpypy import ones
+        a = ones((1, 2, 3))
+        assert a[0, 1, 2] == 1.0
+
+    def test_broadcast_ufunc(self):
+        from numpypy import array
+        a = array([[1, 2], [3, 4], [5, 6]])
+        b = array([5, 6])
+        c = ((a + b) == [[1 + 5, 2 + 6], [3 + 5, 4 + 6], [5 + 5, 6 + 6]])
+        assert c.all()
+
+    def test_broadcast_setslice(self):
+        from numpypy import zeros, ones
+        a = zeros((100, 100))
+        b = ones(100)
+        a[:, :] = b
+        assert a[13, 15] == 1
+
+    def test_broadcast_shape_agreement(self):
+        from numpypy import zeros, array
+        a = zeros((3, 1, 3))
+        b = array(((10, 11, 12), (20, 21, 22), (30, 31, 32)))
+        c = ((a + b) == [b, b, b])
+        assert c.all()
+        a = array((((10, 11, 12), ), ((20, 21, 22), ), ((30, 31, 32), )))
+        assert(a.shape == (3, 1, 3))
+        d = zeros((3, 3))
+        c = ((a + d) == [b, b, b])
+        c = ((a + d) == array([[[10., 11., 12.]] * 3,
+                               [[20., 21., 22.]] * 3, [[30., 31., 32.]] * 3]))
+        assert c.all()
+
+    def test_broadcast_scalar(self):
+        from numpypy import zeros
+        a = zeros((4, 5), 'd')
+        a[:, 1] = 3
+        assert a[2, 1] == 3
+        assert a[0, 2] == 0
+        a[0, :] = 5
+        assert a[0, 3] == 5
+        assert a[2, 1] == 3
+        assert a[3, 2] == 0
+
+    def test_broadcast_call2(self):
+        from numpypy import zeros, ones
+        a = zeros((4, 1, 5))
+        b = ones((4, 3, 5))
+        b[:] = (a + a)
+        assert (b == zeros((4, 3, 5))).all()
+
+    def test_argmax(self):
+        from numpypy import array
+        a = array([[1, 2], [3, 4], [5, 6]])
+        assert a.argmax() == 5
+        assert a[:2, ].argmax() == 3
+
+    def test_broadcast_wrong_shapes(self):
+        from numpypy import zeros
+        a = zeros((4, 3, 2))
+        b = zeros((4, 2))
+        exc = raises(ValueError, lambda: a + b)
+        assert str(exc.value) == "operands could not be broadcast" \
+            " together with shapes (4,3,2) (4,2)"
+
+    def test_reduce(self):
+        from numpypy import array
+        a = array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
+        assert a.sum() == (13 * 12) / 2
+        b = a[1:, 1::2]
+        c = b + b
+        assert c.sum() == (6 + 8 + 10 + 12) * 2
+
+    def test_transpose(self):
+        from numpypy import array
+        a = array(((range(3), range(3, 6)),
+                   (range(6, 9), range(9, 12)),
+                   (range(12, 15), range(15, 18)),
+                   (range(18, 21), range(21, 24))))
+        assert a.shape == (4, 2, 3)
+        b = a.T
+        assert b.shape == (3, 2, 4)
+        assert(b[0, :, 0] == [0, 3]).all()
+        b[:, 0, 0] = 1000
+        assert(a[0, 0, :] == [1000, 1000, 1000]).all()
+        a = array(range(5))
+        b = a.T
+        assert(b == range(5)).all()
+        a = array((range(10), range(20, 30)))
+        b = a.T
+        assert(b[:, 0] == a[0, :]).all()
+
+    def test_flatiter(self):
+        from numpypy import array, flatiter
+        a = array([[10, 30], [40, 60]])
+        f_iter = a.flat
+        assert f_iter.next() == 10
+        assert f_iter.next() == 30
+        assert f_iter.next() == 40
+        assert f_iter.next() == 60
+        raises(StopIteration, "f_iter.next()")
+        raises(TypeError, "flatiter()")
+        s = 0
+        for k in a.flat:
+            s += k
+        assert s == 140
+
+    def test_flatiter_array_conv(self):
+        from numpypy import array, dot
+        a = array([1, 2, 3])
+        assert dot(a.flat, a.flat) == 14
 
 class AppTestSupport(object):
     def setup_class(cls):
@@ -616,8 +982,124 @@
         cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4))
 
     def test_fromstring(self):
-        from numpy import fromstring
+        from numpypy import fromstring
         a = fromstring(self.data)
         for i in range(4):
             assert a[i] == i + 1
         raises(ValueError, fromstring, "abc")
+
+
+class AppTestRepr(BaseNumpyAppTest):
+    def test_repr(self):
+        from numpypy import array, zeros
+        a = array(range(5), float)
+        assert repr(a) == "array([0.0, 1.0, 2.0, 3.0, 4.0])"
+        a = array([], float)
+        assert repr(a) == "array([], dtype=float64)"
+        a = zeros(1001)
+        assert repr(a) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])"
+        a = array(range(5), long)
+        assert repr(a) == "array([0, 1, 2, 3, 4])"
+        a = array([], long)
+        assert repr(a) == "array([], dtype=int64)"
+        a = array([True, False, True, False], "?")
+        assert repr(a) == "array([True, False, True, False], dtype=bool)"
+
+    def test_repr_multi(self):
+        from numpypy import array, zeros
+        a = zeros((3, 4))
+        assert repr(a) == '''array([[0.0, 0.0, 0.0, 0.0],
+       [0.0, 0.0, 0.0, 0.0],
+       [0.0, 0.0, 0.0, 0.0]])'''
+        a = zeros((2, 3, 4))
+        assert repr(a) == '''array([[[0.0, 0.0, 0.0, 0.0],
+        [0.0, 0.0, 0.0, 0.0],
+        [0.0, 0.0, 0.0, 0.0]],
+
+       [[0.0, 0.0, 0.0, 0.0],
+        [0.0, 0.0, 0.0, 0.0],
+        [0.0, 0.0, 0.0, 0.0]]])'''
+
+    def test_repr_slice(self):
+        from numpypy import array, zeros
+        a = array(range(5), float)
+        b = a[1::2]
+        assert repr(b) == "array([1.0, 3.0])"
+        a = zeros(2002)
+        b = a[::2]
+        assert repr(b) == "array([0.0, 0.0, 0.0, ..., 0.0, 0.0, 0.0])"
+        a = array((range(5), range(5, 10)), dtype="int16")
+        b = a[1, 2:]
+        assert repr(b) == "array([7, 8, 9], dtype=int16)"
+        # an empty slice prints its shape
+        b = a[2:1, ]
+        assert repr(b) == "array([], shape=(0, 5), dtype=int16)"
+
+    def test_str(self):
+        from numpypy import array, zeros
+        a = array(range(5), float)
+        assert str(a) == "[0.0 1.0 2.0 3.0 4.0]"
+        assert str((2 * a)[:]) == "[0.0 2.0 4.0 6.0 8.0]"
+        a = zeros(1001)
+        assert str(a) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]"
+
+        a = array(range(5), dtype=long)
+        assert str(a) == "[0 1 2 3 4]"
+        a = array([True, False, True, False], dtype="?")
+        assert str(a) == "[True False True False]"
+
+        a = array(range(5), dtype="int8")
+        assert str(a) == "[0 1 2 3 4]"
+
+        a = array(range(5), dtype="int16")
+        assert str(a) == "[0 1 2 3 4]"
+
+        a = array((range(5), range(5, 10)), dtype="int16")
+        assert str(a) == "[[0 1 2 3 4]\n [5 6 7 8 9]]"
+
+        a = array(3, dtype=int)
+        assert str(a) == "3"
+
+        a = zeros((400, 400), dtype=int)
+        assert str(a) == "[[0 0 0 ..., 0 0 0]\n [0 0 0 ..., 0 0 0]\n" \
+           " [0 0 0 ..., 0 0 0]\n ..., \n [0 0 0 ..., 0 0 0]\n" \
+           " [0 0 0 ..., 0 0 0]\n [0 0 0 ..., 0 0 0]]"
+        a = zeros((2, 2, 2))
+        r = str(a)
+        assert r == '[[[0.0 0.0]\n  [0.0 0.0]]\n\n [[0.0 0.0]\n  [0.0 0.0]]]'
+
+    def test_str_slice(self):
+        from numpypy import array, zeros
+        a = array(range(5), float)
+        b = a[1::2]
+        assert str(b) == "[1.0 3.0]"
+        a = zeros(2002)
+        b = a[::2]
+        assert str(b) == "[0.0 0.0 0.0 ..., 0.0 0.0 0.0]"
+        a = array((range(5), range(5, 10)), dtype="int16")
+        b = a[1, 2:]
+        assert str(b) == "[7 8 9]"
+        b = a[2:1, ]
+        assert str(b) == "[]"
+
+
+class AppTestRanges(BaseNumpyAppTest):
+    def test_arange(self):
+        from numpypy import arange, array, dtype
+        a = arange(3)
+        assert (a == [0, 1, 2]).all()
+        assert a.dtype is dtype(int)
+        a = arange(3.0)
+        assert (a == [0., 1., 2.]).all()
+        assert a.dtype is dtype(float)
+        a = arange(3, 7)
+        assert (a == [3, 4, 5, 6]).all()
+        assert a.dtype is dtype(int)
+        a = arange(3, 7, 2)
+        assert (a == [3, 5]).all()
+        a = arange(3, dtype=float)
+        assert (a == [0., 1., 2.]).all()
+        assert a.dtype is dtype(float)
+        a = arange(0, 0.8, 0.1)
+        assert len(a) == 8
+        assert arange(False, True, True).dtype is dtype(int)
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -4,14 +4,14 @@
 
 class AppTestUfuncs(BaseNumpyAppTest):
     def test_ufunc_instance(self):
-        from numpy import add, ufunc
+        from numpypy import add, ufunc
 
         assert isinstance(add, ufunc)
         assert repr(add) == "<ufunc 'add'>"
         assert repr(ufunc) == "<type 'numpy.ufunc'>"
 
     def test_ufunc_attrs(self):
-        from numpy import add, multiply, sin
+        from numpypy import add, multiply, sin
 
         assert add.identity == 0
         assert multiply.identity == 1
@@ -22,7 +22,7 @@
         assert sin.nin == 1
 
     def test_wrong_arguments(self):
-        from numpy import add, sin
+        from numpypy import add, sin
 
         raises(ValueError, add, 1)
         raises(TypeError, add, 1, 2, 3)
@@ -30,14 +30,14 @@
         raises(ValueError, sin)
 
     def test_single_item(self):
-        from numpy import negative, sign, minimum
+        from numpypy import negative, sign, minimum
 
         assert negative(5.0) == -5.0
         assert sign(-0.0) == 0.0
         assert minimum(2.0, 3.0) == 2.0
 
     def test_sequence(self):
-        from numpy import array, negative, minimum
+        from numpypy import array, negative, minimum
         a = array(range(3))
         b = [2.0, 1.0, 0.0]
         c = 1.0
@@ -71,7 +71,7 @@
             assert min_c_b[i] == min(b[i], c)
 
     def test_negative(self):
-        from numpy import array, negative
+        from numpypy import array, negative
 
         a = array([-5.0, 0.0, 1.0])
         b = negative(a)
@@ -86,7 +86,7 @@
         assert negative(a + a)[3] == -6
 
     def test_abs(self):
-        from numpy import array, absolute
+        from numpypy import array, absolute
 
         a = array([-5.0, -0.0, 1.0])
         b = absolute(a)
@@ -94,7 +94,7 @@
             assert b[i] == abs(a[i])
 
     def test_add(self):
-        from numpy import array, add
+        from numpypy import array, add
 
         a = array([-5.0, -0.0, 1.0])
         b = array([ 3.0, -2.0,-3.0])
@@ -103,7 +103,7 @@
             assert c[i] == a[i] + b[i]
 
     def test_divide(self):
-        from numpy import array, divide
+        from numpypy import array, divide
 
         a = array([-5.0, -0.0, 1.0])
         b = array([ 3.0, -2.0,-3.0])
@@ -112,7 +112,7 @@
             assert c[i] == a[i] / b[i]
 
     def test_fabs(self):
-        from numpy import array, fabs
+        from numpypy import array, fabs
         from math import fabs as math_fabs
 
         a = array([-5.0, -0.0, 1.0])
@@ -121,7 +121,7 @@
             assert b[i] == math_fabs(a[i])
 
     def test_minimum(self):
-        from numpy import array, minimum
+        from numpypy import array, minimum
 
         a = array([-5.0, -0.0, 1.0])
         b = array([ 3.0, -2.0,-3.0])
@@ -130,7 +130,7 @@
             assert c[i] == min(a[i], b[i])
 
     def test_maximum(self):
-        from numpy import array, maximum
+        from numpypy import array, maximum
 
         a = array([-5.0, -0.0, 1.0])
         b = array([ 3.0, -2.0,-3.0])
@@ -143,7 +143,7 @@
         assert isinstance(x, (int, long))
 
     def test_multiply(self):
-        from numpy import array, multiply
+        from numpypy import array, multiply
 
         a = array([-5.0, -0.0, 1.0])
         b = array([ 3.0, -2.0,-3.0])
@@ -152,7 +152,7 @@
             assert c[i] == a[i] * b[i]
 
     def test_sign(self):
-        from numpy import array, sign, dtype
+        from numpypy import array, sign, dtype
 
         reference = [-1.0, 0.0, 0.0, 1.0]
         a = array([-5.0, -0.0, 0.0, 6.0])
@@ -171,7 +171,7 @@
         assert a[1] == 0
 
     def test_reciporocal(self):
-        from numpy import array, reciprocal
+        from numpypy import array, reciprocal
 
         reference = [-0.2, float("inf"), float("-inf"), 2.0]
         a = array([-5.0, 0.0, -0.0, 0.5])
@@ -180,7 +180,7 @@
             assert b[i] == reference[i]
 
     def test_subtract(self):
-        from numpy import array, subtract
+        from numpypy import array, subtract
 
         a = array([-5.0, -0.0, 1.0])
         b = array([ 3.0, -2.0,-3.0])
@@ -189,7 +189,7 @@
             assert c[i] == a[i] - b[i]
 
     def test_floor(self):
-        from numpy import array, floor
+        from numpypy import array, floor
 
         reference = [-2.0, -1.0, 0.0, 1.0, 1.0]
         a = array([-1.4, -1.0, 0.0, 1.0, 1.4])
@@ -198,7 +198,7 @@
             assert b[i] == reference[i]
 
     def test_copysign(self):
-        from numpy import array, copysign
+        from numpypy import array, copysign
 
         reference = [5.0, -0.0, 0.0, -6.0]
         a = array([-5.0, 0.0, 0.0, 6.0])
@@ -214,7 +214,7 @@
 
     def test_exp(self):
         import math
-        from numpy import array, exp
+        from numpypy import array, exp
 
         a = array([-5.0, -0.0, 0.0, 12345678.0, float("inf"),
                    -float('inf'), -12343424.0])
@@ -228,7 +228,7 @@
 
     def test_sin(self):
         import math
-        from numpy import array, sin
+        from numpypy import array, sin
 
         a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2])
         b = sin(a)
@@ -241,7 +241,7 @@
 
     def test_cos(self):
         import math
-        from numpy import array, cos
+        from numpypy import array, cos
 
         a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2])
         b = cos(a)
@@ -250,7 +250,7 @@
 
     def test_tan(self):
         import math
-        from numpy import array, tan
+        from numpypy import array, tan
 
         a = array([0, 1, 2, 3, math.pi, math.pi*1.5, math.pi*2])
         b = tan(a)
@@ -260,7 +260,7 @@
 
     def test_arcsin(self):
         import math
-        from numpy import array, arcsin
+        from numpypy import array, arcsin
 
         a = array([-1, -0.5, -0.33, 0, 0.33, 0.5, 1])
         b = arcsin(a)
@@ -274,7 +274,7 @@
 
     def test_arccos(self):
         import math
-        from numpy import array, arccos
+        from numpypy import array, arccos
 
         a = array([-1, -0.5, -0.33, 0, 0.33, 0.5, 1])
         b = arccos(a)
@@ -289,7 +289,7 @@
 
     def test_arctan(self):
         import math
-        from numpy import array, arctan
+        from numpypy import array, arctan
 
         a = array([-3, -2, -1, 0, 1, 2, 3, float('inf'), float('-inf')])
         b = arctan(a)
@@ -302,7 +302,7 @@
 
     def test_arcsinh(self):
         import math
-        from numpy import arcsinh, inf
+        from numpypy import arcsinh, inf
 
         for v in [inf, -inf, 1.0, math.e]:
             assert math.asinh(v) == arcsinh(v)
@@ -310,7 +310,7 @@
 
     def test_arctanh(self):
         import math
-        from numpy import arctanh
+        from numpypy import arctanh
 
         for v in [.99, .5, 0, -.5, -.99]:
             assert math.atanh(v) == arctanh(v)
@@ -319,14 +319,25 @@
         for v in [1.0, -1.0]:
             assert arctanh(v) == math.copysign(float("inf"), v)
 
+    def test_sqrt(self):
+        import math
+        from numpypy import sqrt
+
+        nan, inf = float("nan"), float("inf")
+        data = [1, 2, 3, inf]
+        results = [math.sqrt(1), math.sqrt(2), math.sqrt(3), inf]
+        assert (sqrt(data) == results).all()
+        assert math.isnan(sqrt(-1))
+        assert math.isnan(sqrt(nan))
+
     def test_reduce_errors(self):
-        from numpy import sin, add
+        from numpypy import sin, add
 
         raises(ValueError, sin.reduce, [1, 2, 3])
         raises(TypeError, add.reduce, 1)
 
     def test_reduce(self):
-        from numpy import add, maximum
+        from numpypy import add, maximum
 
         assert add.reduce([1, 2, 3]) == 6
         assert maximum.reduce([1]) == 1
@@ -335,7 +346,7 @@
 
     def test_comparisons(self):
         import operator
-        from numpy import equal, not_equal, less, less_equal, greater, greater_equal
+        from numpypy import equal, not_equal, less, less_equal, greater, greater_equal
 
         for ufunc, func in [
             (equal, operator.eq),
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
@@ -1,29 +1,54 @@
+
+""" Tests that check if JIT-compiled numpy operations produce reasonably
+good assembler
+"""
+
+import py
+
+from pypy.jit.metainterp import pyjitpl
 from pypy.jit.metainterp.test.support import LLJitMixin
+from pypy.jit.metainterp.warmspot import reset_stats
 from pypy.module.micronumpy import interp_ufuncs, signature
-from pypy.module.micronumpy.compile import (FakeSpace,
-    FloatObject, IntObject, numpy_compile, BoolObject)
-from pypy.module.micronumpy.interp_numarray import (SingleDimArray,
-    SingleDimSlice)
+from pypy.module.micronumpy.compile import (numpy_compile, FakeSpace,
+    FloatObject, IntObject, BoolObject, Parser, InterpreterState)
+from pypy.module.micronumpy.interp_numarray import NDimArray, NDimSlice
 from pypy.rlib.nonconst import NonConstant
 from pypy.rpython.annlowlevel import llstr, hlstr
-from pypy.jit.metainterp.warmspot import reset_stats
-from pypy.jit.metainterp import pyjitpl
-
-import py
 
 
 class TestNumpyJIt(LLJitMixin):
     graph = None
     interp = None
-        
-    def run(self, code):
+
+    def setup_class(cls):
+        default = """
+        a = [1,2,3,4]
+        c = a + b
+        sum(c) -> 1::1
+        a -> 3:1:2
+        """
+
+        d = {}
+        p = Parser()
+        allcodes = [p.parse(default)]
+        for name, meth in cls.__dict__.iteritems():
+            if name.startswith("define_"):
+                code = meth()
+                d[name[len("define_"):]] = len(allcodes)
+                allcodes.append(p.parse(code))
+        cls.code_mapping = d
+        cls.codes = allcodes
+
+    def run(self, name):
         space = FakeSpace()
-        
-        def f(code):
-            interp = numpy_compile(hlstr(code))
+        i = self.code_mapping[name]
+        codes = self.codes
+
+        def f(i):
+            interp = InterpreterState(codes[i])
             interp.run(space)
             res = interp.results[-1]
-            w_res = res.eval(0).wrap(interp.space)
+            w_res = res.eval(res.start_iter()).wrap(interp.space)
             if isinstance(w_res, BoolObject):
                 return float(w_res.boolval)
             elif isinstance(w_res, FloatObject):
@@ -34,62 +59,77 @@
                 return -42.
 
         if self.graph is None:
-            interp, graph = self.meta_interp(f, [llstr(code)],
+            interp, graph = self.meta_interp(f, [i],
                                              listops=True,
                                              backendopt=True,
                                              graph_and_interp_only=True)
             self.__class__.interp = interp
             self.__class__.graph = graph
-
         reset_stats()
         pyjitpl._warmrunnerdesc.memory_manager.alive_loops.clear()
-        return self.interp.eval_graph(self.graph, [llstr(code)])
+        return self.interp.eval_graph(self.graph, [i])
 
-    def test_add(self):
-        result = self.run("""
+    def define_add():
+        return """
         a = |30|
         b = a + a
         b -> 3
-        """)
-        self.check_loops({'getarrayitem_raw': 2, 'float_add': 1,
-                          'setarrayitem_raw': 1, 'int_add': 1,
-                          'int_lt': 1, 'guard_true': 1, 'jump': 1})
+        """
+
+    def test_add(self):
+        result = self.run("add")
+        self.check_resops({'setarrayitem_raw': 2, 'getfield_gc': 19, 'guard_class': 11,
+                           'int_add': 6, 'guard_isnull': 1, 'jump': 2, 'int_ge': 2,
+                           'getarrayitem_raw': 4, 'float_add': 2, 'guard_false': 2,
+                           'guard_value': 1})
         assert result == 3 + 3
 
-    def test_floatadd(self):
-        result = self.run("""
+    def define_float_add():
+        return """
         a = |30| + 3
         a -> 3
-        """)
+        """
+
+    def test_floatadd(self):
+        result = self.run("float_add")
         assert result == 3 + 3
-        self.check_loops({"getarrayitem_raw": 1, "float_add": 1,
-                          "setarrayitem_raw": 1, "int_add": 1,
-                          "int_lt": 1, "guard_true": 1, "jump": 1})
+        self.check_resops({'setarrayitem_raw': 2, 'getfield_gc': 17, 'guard_class': 11,
+                           'int_add': 4, 'guard_isnull': 1, 'jump': 2, 'int_ge': 2,
+                           'getarrayitem_raw': 2, 'float_add': 2, 'guard_false': 2,
+                           'guard_value': 1})
 
-    def test_sum(self):
-        result = self.run("""
+    def define_sum():
+        return """
         a = |30|
         b = a + a
         sum(b)
-        """)
+        """
+
+    def test_sum(self):
+        result = self.run("sum")
         assert result == 2 * sum(range(30))
-        self.check_loops({"getarrayitem_raw": 2, "float_add": 2,
-                          "int_add": 1,
-                          "int_lt": 1, "guard_true": 1, "jump": 1})
+        self.check_resops({'guard_class': 10, 'getfield_gc': 17, 'jump': 2,
+                           'getarrayitem_raw': 4, 'guard_value': 2, 'int_add': 4,
+                           'guard_isnull': 1, 'int_ge': 2, 'float_add': 4, 'guard_false': 2})
 
-    def test_prod(self):
-        result = self.run("""
+    def define_prod():
+        return """
         a = |30|
         b = a + a
         prod(b)
-        """)
+        """
+
+    def test_prod(self):
+        result = self.run("prod")
         expected = 1
         for i in range(30):
             expected *= i * 2
         assert result == expected
-        self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
-                          "float_mul": 1, "int_add": 1,
-                          "int_lt": 1, "guard_true": 1, "jump": 1})
+        self.check_resops({'guard_class': 10, 'getfield_gc': 17, 'int_add': 4,
+                           'float_mul': 2, 'guard_isnull': 1, 'jump': 2, 'int_ge': 2,
+                           'getarrayitem_raw': 4, 'float_add': 2, 'guard_false': 2,
+                           'guard_value': 2})
+
 
     def test_max(self):
         py.test.skip("broken, investigate")
@@ -113,54 +153,68 @@
         min(b)
         """)
         assert result == -24
-        self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
-                          "float_mul": 1, "int_add": 1,
-                          "int_lt": 1, "guard_true": 1, "jump": 1})
+        self.check_resops({'guard_class': 10, 'getfield_gc': 15, 'guard_value': 1,
+                           'int_add': 4, 'guard_isnull': 1, 'jump': 2, 'int_ge': 2,
+                           'getarrayitem_raw': 4, 'float_add': 2, 'guard_false': 4,
+                           'float_ne': 2})
 
-    def test_any(self):
-        result = self.run("""
+    def define_any():
+        return """
         a = [0,0,0,0,0,0,0,0,0,0,0]
         a[8] = -12
         b = a + a
         any(b)
-        """)
+        """
+
+    def test_any(self):
+        result = self.run("any")
         assert result == 1
-        self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
-                          "float_ne": 1, "int_add": 1,
-                          "int_lt": 1, "guard_true": 1, "jump": 1,
-                          "guard_false": 1})
+        self.check_resops({'guard_class': 10, 'getfield_gc': 15, 'guard_value': 1,
+                           'int_add': 4, 'guard_isnull': 1, 'jump': 2, 'int_ge': 2,
+                           'getarrayitem_raw': 4, 'float_add': 2, 'guard_false': 4,
+                           'float_ne': 2})
 
-    def test_already_forced(self):
-        result = self.run("""
+    def define_already_forced():
+        return """
         a = |30|
         b = a + 4.5
         b -> 5 # forces
         c = b * 8
         c -> 5
-        """)
+        """
+
+    def test_already_forced(self):
+        result = self.run("already_forced")
         assert result == (5 + 4.5) * 8
         # 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.
-        self.check_loops({"getarrayitem_raw": 2, "float_mul": 1, "float_add": 1,
-                           "setarrayitem_raw": 2, "int_add": 2,
-                           "int_lt": 2, "guard_true": 2, "jump": 2})
+        self.check_resops({'setarrayitem_raw': 4, 'guard_nonnull': 1, 'getfield_gc': 35,
+                           'guard_class': 22, 'int_add': 8, 'float_mul': 2,
+                           'guard_isnull': 2, 'jump': 4, 'int_ge': 4,
+                           'getarrayitem_raw': 4, 'float_add': 2, 'guard_false': 4,
+                           'guard_value': 2})
 
-    def test_ufunc(self):
-        result = self.run("""
+
+    def define_ufunc():
+        return """
         a = |30|
         b = a + a
         c = unegative(b)
         c -> 3
-        """)
+        """
+
+    def test_ufunc(self):
+        result = self.run("ufunc")
         assert result == -6
-        self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "float_neg": 1,
-                          "setarrayitem_raw": 1, "int_add": 1,
-                          "int_lt": 1, "guard_true": 1, "jump": 1,
-        })
+        self.check_resops({'setarrayitem_raw': 2, 'getfield_gc': 24, 'guard_class': 14,
+                           'int_add': 6, 'float_neg': 2, 'guard_isnull': 2, 'jump': 2,
+                           'int_ge': 2, 'getarrayitem_raw': 4, 'float_add': 2,
+                           'guard_false': 2, 'guard_value': 2})
 
-    def test_specialization(self):
-        self.run("""
+
+    def define_specialization():
+        return """
         a = |30|
         b = a + a
         c = unegative(b)
@@ -177,49 +231,98 @@
         d = a * a
         unegative(d)
         d -> 3
-        """)
+        """
+
+    def test_specialization(self):
+        self.run("specialization")
         # This is 3, not 2 because there is a bridge for the exit.
         self.check_loop_count(3)
 
+    def define_slice():
+        return """
+        a = |30|
+        b = a -> ::3
+        c = b + b
+        c -> 3
+        """
+
+    def test_slice(self):
+        result = self.run("slice")
+        assert result == 18
+        py.test.skip("Few remaining arraylen_gc left")
+        self.check_loops({'int_mul': 2, 'getarrayitem_raw': 2, 'float_add': 1,
+                          'setarrayitem_raw': 1, 'int_add': 3,
+                          'int_lt': 1, 'guard_true': 1, 'jump': 1})
+
+    def define_multidim():
+        return """
+        a = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
+        b = a + a
+        b -> 1 -> 1
+        """
+
+    def test_multidim(self):
+        result = self.run('multidim')
+        assert result == 8
+        self.check_resops({'setarrayitem_raw': 2, 'getfield_gc': 19, 'guard_class': 11,
+                           'int_add': 6, 'guard_isnull': 1, 'jump': 2, 'int_ge': 2,
+                           'getarrayitem_raw': 4, 'float_add': 2, 'guard_false': 2,
+                           'guard_value': 1})
+        # int_add might be 1 here if we try slightly harder with
+        # reusing indexes or some optimization
+
+    def define_multidim_slice():
+        return """
+        a = [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8], [7, 8, 9, 10], [9, 10, 11, 12], [11, 12, 13, 14], [13, 14, 15, 16], [16, 17, 18, 19]]
+        b = a -> ::2
+        c = b + b
+        c -> 1 -> 1
+        """
+
+    def test_multidim_slice(self):
+        result = self.run('multidim_slice')
+        assert result == 12
+        py.test.skip("improve")
+        # XXX the bridge here is scary. Hopefully jit-targets will fix that,
+        #     otherwise it looks kind of good
+        self.check_loops({})
+
+    def define_broadcast():
+        return """
+        a = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
+        b = [1, 2, 3, 4]
+        c = a + b
+        c -> 1 -> 2
+        """
+
+    def test_broadcast(self):
+        result = self.run("broadcast")
+        assert result == 10
+        py.test.skip("improve")
+        self.check_loops({})
 
 class TestNumpyOld(LLJitMixin):
     def setup_class(cls):
+        py.test.skip("old")
         from pypy.module.micronumpy.compile import FakeSpace
         from pypy.module.micronumpy.interp_dtype import W_Float64Dtype
-        
+
         cls.space = FakeSpace()
         cls.float64_dtype = cls.space.fromcache(W_Float64Dtype)
-    
-    def test_slice(self):
-        def f(i):
-            step = 3
-            ar = SingleDimArray(step*i, dtype=self.float64_dtype)
-            new_sig = signature.Signature.find_sig([
-                SingleDimSlice.signature, ar.signature
-            ])
-            s = SingleDimSlice(0, step*i, step, i, ar, new_sig)
-            v = interp_ufuncs.get(self.space).add.call(self.space, [s, s])
-            return v.get_concrete().eval(3).val
-
-        result = self.meta_interp(f, [5], listops=True, backendopt=True)
-        self.check_loops({'int_mul': 1, 'getarrayitem_raw': 2, 'float_add': 1,
-                          'setarrayitem_raw': 1, 'int_add': 1,
-                          'int_lt': 1, 'guard_true': 1, 'jump': 1})
-        assert result == f(5)
 
     def test_slice2(self):
         def f(i):
             step1 = 2
             step2 = 3
-            ar = SingleDimArray(step2*i, dtype=self.float64_dtype)
+            ar = NDimArray(step2*i, dtype=self.float64_dtype)
             new_sig = signature.Signature.find_sig([
-                SingleDimSlice.signature, ar.signature
+                NDimSlice.signature, ar.signature
             ])
-            s1 = SingleDimSlice(0, step1*i, step1, i, ar, new_sig)
+            s1 = NDimSlice(0, step1*i, step1, i, ar, new_sig)
             new_sig = signature.Signature.find_sig([
-                SingleDimSlice.signature, s1.signature
+                NDimSlice.signature, s1.signature
             ])
-            s2 = SingleDimSlice(0, step2*i, step2, i, ar, new_sig)
+            s2 = NDimSlice(0, step2*i, step2, i, ar, new_sig)
             v = interp_ufuncs.get(self.space).add.call(self.space, [s1, s2])
             return v.get_concrete().eval(3).val
 
@@ -235,8 +338,8 @@
 
         def f(i):
             step = NonConstant(3)
-            ar = SingleDimArray(step*i, dtype=float64_dtype)
-            ar2 = SingleDimArray(i, dtype=float64_dtype)
+            ar = NDimArray(step*i, dtype=float64_dtype)
+            ar2 = NDimArray(i, dtype=float64_dtype)
             ar2.get_concrete().setitem(1, float64_dtype.box(5.5))
             arg = ar2.descr_add(space, ar2)
             ar.setslice(space, 0, step*i, step, i, arg)
@@ -262,7 +365,7 @@
                 dtype = float64_dtype
             else:
                 dtype = int32_dtype
-            ar = SingleDimArray(n, dtype=dtype)
+            ar = NDimArray(n, [n], dtype=dtype)
             i = 0
             while i < n:
                 ar.get_concrete().setitem(i, int32_dtype.box(7))
diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py
--- a/pypy/module/pyexpat/interp_pyexpat.py
+++ b/pypy/module/pyexpat/interp_pyexpat.py
@@ -3,9 +3,7 @@
 from pypy.interpreter.gateway import NoneNotWrapped
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.error import OperationError
-from pypy.objspace.descroperation import object_setattr
 from pypy.rlib import rgc
-from pypy.rlib.unroll import unrolling_iterable
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.tool import rffi_platform
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -339,8 +337,6 @@
     'XML_SetUnknownEncodingHandler',
     [XML_Parser, callback_type, rffi.VOIDP], lltype.Void)
 
-ENUMERATE_SETTERS = unrolling_iterable(SETTERS.items())
-
 # Declarations of external functions
 
 XML_ParserCreate = expat_external(
@@ -545,15 +541,19 @@
                 self.buffer_used = 0
         return False
 
+    def gethandler(self, space, name, index):
+        if name == 'CharacterDataHandler':
+            return self.w_character_data_handler or space.w_None
+        return self.handlers[index]
+
     def sethandler(self, space, name, w_handler, index, setter, handler):
-
         if name == 'CharacterDataHandler':
             self.flush_character_buffer(space)
             if space.is_w(w_handler, space.w_None):
                 self.w_character_data_handler = None
             else:
                 self.w_character_data_handler = w_handler
-
+        #
         self.handlers[index] = w_handler
         setter(self.itself, handler)
 
@@ -580,21 +580,29 @@
         return True
 
 
-    @unwrap_spec(name=str)
-    def setattr(self, space, name, w_value):
-        if name == "namespace_prefixes":
-            XML_SetReturnNSTriplet(self.itself, space.int_w(w_value))
-            return
+    @staticmethod
+    def _make_property(name):
+        index, setter, handler = SETTERS[name]
+        #
+        def descr_get_property(self, space):
+            return self.gethandler(space, name, index)
+        #
+        def descr_set_property(self, space, w_value):
+            return self.sethandler(space, name, w_value,
+                                   index, setter, handler)
+        #
+        return GetSetProperty(descr_get_property,
+                              descr_set_property,
+                              cls=W_XMLParserType)
 
-        for handler_name, (index, setter, handler) in ENUMERATE_SETTERS:
-            if name == handler_name:
-                return self.sethandler(space, handler_name, w_value,
-                                       index, setter, handler)
 
-        # fallback to object.__setattr__()
-        return space.call_function(
-            object_setattr(space),
-            space.wrap(self), space.wrap(name), w_value)
+    def get_namespace_prefixes(self, space):
+        raise OperationError(space.w_AttributeError,
+            space.wrap("not implemented: reading namespace_prefixes"))
+
+    @unwrap_spec(value=int)
+    def set_namespace_prefixes(self, space, value):
+        XML_SetReturnNSTriplet(self.itself, bool(value))
 
     # Parse methods
 
@@ -732,10 +740,18 @@
 if XML_COMBINED_VERSION >= 19505:
     XMLParser_methods.append('UseForeignDTD')
 
+_XMLParser_extras = {}
+for name in XMLParser_methods:
+    _XMLParser_extras[name] = interp2app(getattr(W_XMLParserType, name))
+for name in SETTERS:
+    _XMLParser_extras[name] = W_XMLParserType._make_property(name)
+
 W_XMLParserType.typedef = TypeDef(
     "pyexpat.XMLParserType",
     __doc__ = "XML parser",
-    __setattr__ = interp2app(W_XMLParserType.setattr),
+    namespace_prefixes = GetSetProperty(W_XMLParserType.get_namespace_prefixes,
+                                        W_XMLParserType.set_namespace_prefixes,
+                                        cls=W_XMLParserType),
     returns_unicode = bool_property('returns_unicode', W_XMLParserType),
     ordered_attributes = bool_property('ordered_attributes', W_XMLParserType),
     specified_attributes = bool_property('specified_attributes', W_XMLParserType),
@@ -754,8 +770,7 @@
     CurrentColumnNumber = GetSetProperty(W_XMLParserType.descr_ErrorColumnNumber, cls=W_XMLParserType),
     CurrentByteIndex = GetSetProperty(W_XMLParserType.descr_ErrorByteIndex, cls=W_XMLParserType),
 
-    **dict((name, interp2app(getattr(W_XMLParserType, name)))
-           for name in XMLParser_methods)
+    **_XMLParser_extras
     )
 
 def ParserCreate(space, w_encoding=None, w_namespace_separator=None,
diff --git a/pypy/module/pyexpat/test/test_parser.py b/pypy/module/pyexpat/test/test_parser.py
--- a/pypy/module/pyexpat/test/test_parser.py
+++ b/pypy/module/pyexpat/test/test_parser.py
@@ -52,6 +52,19 @@
                 assert res == 1
                 assert data == [u"\u00f6"]
 
+    def test_get_handler(self):
+        import pyexpat
+        p = pyexpat.ParserCreate()
+        assert p.StartElementHandler is None
+        assert p.EndElementHandler is None
+        def f(*args): pass
+        p.StartElementHandler = f
+        assert p.StartElementHandler is f
+        def g(*args): pass
+        p.EndElementHandler = g
+        assert p.StartElementHandler is f
+        assert p.EndElementHandler is g
+
     def test_intern(self):
         import pyexpat
         p = pyexpat.ParserCreate()
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -6,6 +6,7 @@
 from pypy.tool.pairtype import extendabletype
 from pypy.rlib.rarithmetic import r_uint, intmask
 from pypy.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside
+from pypy.rlib import jit
 from pypy.rlib.jit import current_trace_length, unroll_parameters
 import pypy.interpreter.pyopcode   # for side-effects
 from pypy.interpreter.error import OperationError, operationerrfmt
@@ -200,18 +201,18 @@
     if len(args_w) == 1:
         text = space.str_w(args_w[0])
         try:
-            pypyjitdriver.set_user_param(text)
+            jit.set_user_param(None, text)
         except ValueError:
             raise OperationError(space.w_ValueError,
                                  space.wrap("error in JIT parameters string"))
     for key, w_value in kwds_w.items():
         if key == 'enable_opts':
-            pypyjitdriver.set_param('enable_opts', space.str_w(w_value))
+            jit.set_param(None, 'enable_opts', space.str_w(w_value))
         else:
             intval = space.int_w(w_value)
             for name, _ in unroll_parameters:
                 if name == key and name != 'enable_opts':
-                    pypyjitdriver.set_param(name, intval)
+                    jit.set_param(None, name, intval)
                     break
             else:
                 raise operationerrfmt(space.w_TypeError,
diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py
--- a/pypy/module/pypyjit/policy.py
+++ b/pypy/module/pypyjit/policy.py
@@ -17,7 +17,7 @@
                        'imp', 'sys', 'array', '_ffi', 'itertools', 'operator',
                        'posix', '_socket', '_sre', '_lsprof', '_weakref',
                        '__pypy__', 'cStringIO', '_collections', 'struct',
-                       'mmap']:
+                       'mmap', 'marshal']:
             return True
         return False
 
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
@@ -271,7 +271,7 @@
         thread_ticker_check = """
             guard_not_invalidated?
             ticker0 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
-            ticker1 = int_sub(ticker0, 1)
+            ticker1 = int_sub(ticker0, _)
             setfield_raw(ticker_address, ticker1, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
             ticker_cond0 = int_lt(ticker1, 0)
             guard_false(ticker_cond0, descr=...)
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
@@ -334,26 +334,27 @@
         log = self.run(main, [1000])
         assert log.result == (1000, 998)
         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 .*>)
             i15 = int_add(i13, 1)
             # Will be killed by the backend
-            i17 = arraylen_gc(p7, descr=<GcPtrArrayDescr>)
-            call(ConstClass(_ll_list_resize_ge), p8, i15, descr=<VoidCallDescr>)
+            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__...
             guard_no_exception(descr=...)
             p17 = getfield_gc(p8, descr=<GcPtrFieldDescr list.items .*>)
-            p19 = new_with_vtable(ConstClass(W_IntObject))
-            setfield_gc(p19, i12, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
-            setarrayitem_gc(p17, i13, p19, descr=<GcPtrArrayDescr>)
+            setarrayitem_gc(p17, i13, i12, descr=<SignedArrayDescr>)
         """)
 
     def test_blockstack_virtualizable(self):
         def main(n):
             from pypyjit import residual_call
+            l = len
             i = 0
             while i < n:
                 try:
-                    residual_call(len, [])   # ID: call
+                    residual_call(l, [])   # ID: call
                 except:
                     pass
                 i += 1
@@ -369,11 +370,8 @@
             p22 = new_with_vtable(19511408)
             p24 = new_array(1, descr=<GcPtrArrayDescr>)
             p26 = new_with_vtable(ConstClass(W_ListObject))
-            p27 = new(descr=<SizeDescr .*>)
-            p29 = new_array(0, descr=<GcPtrArrayDescr>)
             setfield_gc(p0, i20, descr=<SignedFieldDescr .*PyFrame.vable_token .*>)
-            setfield_gc(p27, p29, descr=<GcPtrFieldDescr list.items .*>)
-            setfield_gc(p26, p27, descr=<.* .*W_ListObject.inst_wrappeditems .*>)
+            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>)
@@ -486,4 +484,4 @@
             i4 = int_add(i0, 1)
             --TICK--
             jump(..., descr=...)
-        """)
\ No newline at end of file
+        """)
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
@@ -201,9 +201,11 @@
         assert log.result == 1000000
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
-            i16 = int_ge(i12, i13)
+            i14 = getfield_gc(p12, descr=<SignedFieldDescr list.length .*>)
+            i16 = uint_ge(i12, i14)
             guard_false(i16, descr=...)
-            p17 = getarrayitem_gc(p15, i12, descr=<GcPtrArrayDescr>)
+            p16 = getfield_gc(p12, descr=<GcPtrFieldDescr list.items .*>)
+            p17 = getarrayitem_gc(p16, i12, descr=<GcPtrArrayDescr>)
             i19 = int_add(i12, 1)
             setfield_gc(p9, i19, descr=<SignedFieldDescr .*W_AbstractSeqIterObject.inst_index .*>)
             guard_nonnull_class(p17, 146982464, descr=...)
@@ -217,7 +219,7 @@
             i28 = int_add_ovf(i10, i25)
             guard_no_overflow(descr=...)
             --TICK--
-            jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, i19, i13, p14, p15, descr=<Loop0>)
+            jump(p0, p1, p2, p3, p4, p5, p6, i28, i25, p9, p10, p11, p12, i19, descr=<Loop0>)
         """)
 
 
@@ -337,7 +339,7 @@
             a = compile('x+x+x+x+x+x', 'eval', 'eval')
             b = {'x': 7}
             while i < 1000:
-                y = eval(a,b,b)  # ID: eval
+                y = eval(a, b, b)  # ID: eval
                 i += 1
             return y
 
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
@@ -147,8 +147,8 @@
             i31 = int_gt(i30, 23)
             guard_false(i31, descr=...)
             copystrcontent(p9, p21, 0, i25, i10)
-            i33 = int_eq(i30, 23)
-            guard_false(i33, descr=...)
+            i33 = int_lt(i30, 23)
+            guard_true(i33, descr=...)
             p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=<GcPtrCallDescr>)
             guard_no_exception(descr=...)
             i37 = strlen(p35)
diff --git a/pypy/objspace/flow/objspace.py b/pypy/objspace/flow/objspace.py
--- a/pypy/objspace/flow/objspace.py
+++ b/pypy/objspace/flow/objspace.py
@@ -96,6 +96,12 @@
         self.executioncontext.recorder = previous_recorder
         self.concrete_mode -= 1
 
+    def is_w(self, w_one, w_two):
+        return self.is_true(self.is_(w_one, w_two))
+
+    is_ = None     # real version added by add_operations()
+    id  = None     # real version added by add_operations()
+
     def newdict(self):
         if self.concrete_mode:
             return Constant({})
diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py
--- a/pypy/objspace/flow/operation.py
+++ b/pypy/objspace/flow/operation.py
@@ -315,7 +315,7 @@
 del _add_exceptions, _add_except_ovf
 
 def make_op(fs, name, symbol, arity, specialnames):
-    if hasattr(fs, name):
+    if getattr(fs, name, None) is not None:
         return
 
     op = None
diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -9,10 +9,7 @@
 from pypy.rlib.debug import check_annotation
 from pypy.objspace.std import stringobject
 from pypy.objspace.std.intobject import W_IntObject
-from pypy.objspace.std.listobject import (
-    _delitem_slice_helper, _setitem_slice_helper,
-    get_positive_index
-)
+from pypy.objspace.std.listobject import get_positive_index
 from pypy.objspace.std.listtype import get_list_index
 from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
 from pypy.objspace.std.stringobject import W_StringObject
@@ -600,7 +597,7 @@
     oldsize = len(w_bytearray.data)
     start, stop, step, slicelength = w_slice.indices4(space, oldsize)
     sequence2 = makebytearraydata_w(space, w_other)
-    setitem_slice_helper(space, w_bytearray.data, start, step, slicelength, sequence2, empty_elem='\x00')
+    _setitem_slice_helper(space, w_bytearray.data, start, step, slicelength, sequence2, empty_elem='\x00')
 
 def delitem__Bytearray_ANY(space, w_bytearray, w_idx):
     idx = get_list_index(space, w_idx)
@@ -614,13 +611,84 @@
 def delitem__Bytearray_Slice(space, w_bytearray, w_slice):
     start, stop, step, slicelength = w_slice.indices4(space,
                                                       len(w_bytearray.data))
-    delitem_slice_helper(space, w_bytearray.data, start, step, slicelength)
+    _delitem_slice_helper(space, w_bytearray.data, start, step, slicelength)
 
-# create new helper functions with different list type specialisation
-delitem_slice_helper = func_with_new_name(_delitem_slice_helper,
-                                          'delitem_slice_helper')
-setitem_slice_helper = func_with_new_name(_setitem_slice_helper,
-                                          'setitem_slice_helper')
+#XXX share the code again with the stuff in listobject.py
+def _delitem_slice_helper(space, items, start, step, slicelength):
+    if slicelength==0:
+        return
+
+    if step < 0:
+        start = start + step * (slicelength-1)
+        step = -step
+
+    if step == 1:
+        assert start >= 0
+        assert slicelength >= 0
+        del items[start:start+slicelength]
+    else:
+        n = len(items)
+        i = start
+
+        for discard in range(1, slicelength):
+            j = i+1
+            i += step
+            while j < i:
+                items[j-discard] = items[j]
+                j += 1
+
+        j = i+1
+        while j < n:
+            items[j-slicelength] = items[j]
+            j += 1
+        start = n - slicelength
+        assert start >= 0 # annotator hint
+        del items[start:]
+
+def _setitem_slice_helper(space, items, start, step, slicelength, sequence2,
+                          empty_elem):
+    assert slicelength >= 0
+    oldsize = len(items)
+    len2 = len(sequence2)
+    if step == 1:  # Support list resizing for non-extended slices
+        delta = slicelength - len2
+        if delta < 0:
+            delta = -delta
+            newsize = oldsize + delta
+            # XXX support this in rlist!
+            items += [empty_elem] * delta
+            lim = start+len2
+            i = newsize - 1
+            while i >= lim:
+                items[i] = items[i-delta]
+                i -= 1
+        elif start >= 0:
+            del items[start:start+delta]
+        else:
+            assert delta==0   # start<0 is only possible with slicelength==0
+    elif len2 != slicelength:  # No resize for extended slices
+        raise operationerrfmt(space.w_ValueError, "attempt to "
+              "assign sequence of size %d to extended slice of size %d",
+              len2, slicelength)
+
+    if sequence2 is items:
+        if step > 0:
+            # Always copy starting from the right to avoid
+            # having to make a shallow copy in the case where
+            # the source and destination lists are the same list.
+            i = len2 - 1
+            start += i*step
+            while i >= 0:
+                items[start] = sequence2[i]
+                start -= step
+                i -= 1
+            return
+        else:
+            # Make a shallow copy to more easily handle the reversal case
+            sequence2 = list(sequence2)
+    for i in range(len2):
+        items[start] = sequence2[i]
+        start += step
 
 def _strip(space, w_bytearray, u_chars, left, right):
     # note: mostly copied from stringobject._strip
diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py
--- a/pypy/objspace/std/celldict.py
+++ b/pypy/objspace/std/celldict.py
@@ -65,11 +65,11 @@
         if isinstance(cell, ModuleCell):
             cell.w_value = w_value
             return
-        # If the new value and the current value are the same, don't create a
-        # level of indirection, or mutate are version.
-        if self.space.is_w(w_value, cell):
-            return
         if cell is not None:
+            # If the new value and the current value are the same, don't create a
+            # level of indirection, or mutate the version.
+            if self.space.is_w(w_value, cell):
+                return
             w_value = ModuleCell(w_value)
         self.mutated()
         self.unerase(w_dict.dstorage)[key] = w_value
diff --git a/pypy/objspace/std/complexobject.py b/pypy/objspace/std/complexobject.py
--- a/pypy/objspace/std/complexobject.py
+++ b/pypy/objspace/std/complexobject.py
@@ -5,12 +5,46 @@
 from pypy.objspace.std.register_all import register_all
 from pypy.objspace.std.floatobject import W_FloatObject, _hash_float
 from pypy.objspace.std.longobject import W_LongObject
+from pypy.rlib.rbigint import rbigint
 from pypy.rlib.rfloat import (
     formatd, DTSF_STR_PRECISION, isinf, isnan, copysign)
 
 import math
 
-class W_ComplexObject(W_Object):
+
+class W_AbstractComplexObject(W_Object):
+    __slots__ = ()
+
+    def is_w(self, space, w_other):
+        from pypy.rlib.longlong2float import float2longlong
+        if not isinstance(w_other, W_AbstractComplexObject):
+            return False
+        if self.user_overridden_class or w_other.user_overridden_class:
+            return self is w_other
+        real1 = space.float_w(space.getattr(self,    space.wrap("real")))
+        real2 = space.float_w(space.getattr(w_other, space.wrap("real")))
+        imag1 = space.float_w(space.getattr(self,    space.wrap("imag")))
+        imag2 = space.float_w(space.getattr(w_other, space.wrap("imag")))
+        real1 = float2longlong(real1)
+        real2 = float2longlong(real2)
+        imag1 = float2longlong(imag1)
+        imag2 = float2longlong(imag2)
+        return real1 == real2 and imag1 == imag2
+
+    def unique_id(self, space):
+        if self.user_overridden_class:
+            return W_Object.unique_id(self, space)
+        from pypy.rlib.longlong2float import float2longlong
+        from pypy.objspace.std.model import IDTAG_COMPLEX as tag
+        real = space.float_w(space.getattr(self, space.wrap("real")))
+        imag = space.float_w(space.getattr(self, space.wrap("imag")))
+        real_b = rbigint.fromrarith_int(float2longlong(real))
+        imag_b = rbigint.fromrarith_int(float2longlong(imag))
+        val = real_b.lshift(64).or_(imag_b).lshift(3).or_(rbigint.fromint(tag))
+        return space.newlong_from_rbigint(val)
+
+
+class W_ComplexObject(W_AbstractComplexObject):
     """This is a reimplementation of the CPython "PyComplexObject"
     """
     from pypy.objspace.std.complextype import complex_typedef as typedef
diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -21,10 +21,33 @@
 import math
 from pypy.objspace.std.intobject import W_IntObject
 
-class W_FloatObject(W_Object):
-    """This is a reimplementation of the CPython "PyFloatObject"
-       it is assumed that the constructor takes a real Python float as
-       an argument"""
+class W_AbstractFloatObject(W_Object):
+    __slots__ = ()
+
+    def is_w(self, space, w_other):
+        from pypy.rlib.longlong2float import float2longlong
+        if not isinstance(w_other, W_AbstractFloatObject):
+            return False
+        if self.user_overridden_class or w_other.user_overridden_class:
+            return self is w_other
+        one = float2longlong(space.float_w(self))
+        two = float2longlong(space.float_w(w_other))
+        return one == two
+
+    def unique_id(self, space):
+        if self.user_overridden_class:
+            return W_Object.unique_id(self, space)
+        from pypy.rlib.longlong2float import float2longlong
+        from pypy.objspace.std.model import IDTAG_FLOAT as tag
+        val = float2longlong(space.float_w(self))
+        b = rbigint.fromrarith_int(val)
+        b = b.lshift(3).or_(rbigint.fromint(tag))
+        return space.newlong_from_rbigint(b)
+
+
+class W_FloatObject(W_AbstractFloatObject):
+    """This is a implementation of the app-level 'float' type.
+    The constructor takes an RPython float as an argument."""
     from pypy.objspace.std.floattype import float_typedef as typedef
     _immutable_fields_ = ['floatval']
 
diff --git a/pypy/objspace/std/frame.py b/pypy/objspace/std/frame.py
--- a/pypy/objspace/std/frame.py
+++ b/pypy/objspace/std/frame.py
@@ -3,13 +3,11 @@
 import operator
 
 from pypy.rlib.unroll import unrolling_iterable
-from pypy.interpreter import pyopcode, function
+from pypy.interpreter import pyopcode
 from pypy.interpreter.pyframe import PyFrame
-from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.module.__builtin__ import Module
+from pypy.interpreter.error import OperationError
 from pypy.objspace.std import intobject, smallintobject
 from pypy.objspace.std.multimethod import FailedToImplement
-from pypy.objspace.std.dictmultiobject import W_DictMultiObject
 from pypy.objspace.std.listobject import W_ListObject
 
 
@@ -58,7 +56,7 @@
     w_1 = f.popvalue()
     if type(w_1) is W_ListObject and type(w_2) is intobject.W_IntObject:
         try:
-            w_result = w_1.wrappeditems[w_2.intval]
+            w_result = w_1.getitem(w_2.intval)
         except IndexError:
             raise OperationError(f.space.w_IndexError,
                 f.space.wrap("list index out of range"))
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -19,6 +19,22 @@
 class W_AbstractIntObject(W_Object):
     __slots__ = ()
 
+    def is_w(self, space, w_other):
+        if not isinstance(w_other, W_AbstractIntObject):
+            return False
+        if self.user_overridden_class or w_other.user_overridden_class:
+            return self is w_other
+        return space.int_w(self) == space.int_w(w_other)
+
+    def unique_id(self, space):
+        if self.user_overridden_class:
+            return W_Object.unique_id(self, space)
+        from pypy.objspace.std.model import IDTAG_INT as tag
+        b = space.bigint_w(self)
+        b = b.lshift(3).or_(rbigint.fromint(tag))
+        return space.newlong_from_rbigint(b)
+
+
 class W_IntObject(W_AbstractIntObject):
     __slots__ = 'intval'
     _immutable_fields_ = ['intval']
diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py
--- a/pypy/objspace/std/iterobject.py
+++ b/pypy/objspace/std/iterobject.py
@@ -33,9 +33,9 @@
     """Sequence iterator specialized for lists, accessing
     directly their RPython-level list of wrapped objects.
     """
-    def __init__(w_self, w_seq, wrappeditems):
+    def __init__(w_self, w_seq):
         W_AbstractSeqIterObject.__init__(w_self, w_seq)
-        w_self.listitems = wrappeditems
+        w_self.w_seq = w_seq
 
 class W_FastTupleIterObject(W_AbstractSeqIterObject):
    """Sequence iterator specialized for tuples, accessing
@@ -105,13 +105,15 @@
     return w_seqiter
 
 def next__FastListIter(space, w_seqiter):
-    if w_seqiter.listitems is None:
+    from pypy.objspace.std.listobject import W_ListObject
+    w_seq = w_seqiter.w_seq
+    if w_seq is None:
         raise OperationError(space.w_StopIteration, space.w_None)
+    assert isinstance(w_seq, W_ListObject)
     index = w_seqiter.index
     try:
-        w_item = w_seqiter.listitems[index]
+        w_item = w_seq.getitem(index)
     except IndexError:
-        w_seqiter.listitems = None
         w_seqiter.w_seq = None
         raise OperationError(space.w_StopIteration, space.w_None) 
     w_seqiter.index = index + 1
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -5,35 +5,937 @@
 from pypy.objspace.std.inttype import wrapint
 from pypy.objspace.std.listtype import get_list_index
 from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
-
 from pypy.objspace.std import slicetype
 from pypy.interpreter import gateway, baseobjspace
+from pypy.rlib.objectmodel import instantiate, specialize
 from pypy.rlib.listsort import make_timsort_class
+from pypy.rlib import rerased, jit
 from pypy.interpreter.argument import Signature
 
+UNROLL_CUTOFF = 5
+
 class W_AbstractListObject(W_Object):
     __slots__ = ()
 
+def make_range_list(space, start, step, length):
+    if length <= 0:
+        strategy = space.fromcache(EmptyListStrategy)
+        storage = strategy.erase(None)
+    else:
+        strategy = space.fromcache(RangeListStrategy)
+        storage = strategy.erase((start, step, length))
+    return W_ListObject.from_storage_and_strategy(space, storage, strategy)
+
+def make_empty_list(space):
+    strategy = space.fromcache(EmptyListStrategy)
+    storage = strategy.erase(None)
+    return W_ListObject.from_storage_and_strategy(space, storage, strategy)
+
+ at jit.look_inside_iff(lambda space, list_w: jit.isconstant(len(list_w)) and len(list_w) < UNROLL_CUTOFF)
+def get_strategy_from_list_objects(space, list_w):
+    if not list_w:
+        return space.fromcache(EmptyListStrategy)
+
+    # check for ints
+    for w_obj in list_w:
+        if not is_W_IntObject(w_obj):
+            break
+    else:
+        return space.fromcache(IntegerListStrategy)
+
+    # check for strings
+    for w_obj in list_w:
+        if not is_W_StringObject(w_obj):
+            break
+    else:
+        return space.fromcache(StringListStrategy)
+
+    return space.fromcache(ObjectListStrategy)
+
+def is_W_IntObject(w_object):
+    from pypy.objspace.std.intobject import W_IntObject
+    return type(w_object) is W_IntObject
+
+def is_W_StringObject(w_object):
+    from pypy.objspace.std.stringobject import W_StringObject
+    return type(w_object) is W_StringObject
+
+
+
 class W_ListObject(W_AbstractListObject):
     from pypy.objspace.std.listtype import list_typedef as typedef
 
-    def __init__(w_self, wrappeditems):
-        w_self.wrappeditems = wrappeditems
+    def __init__(w_self, space, wrappeditems):
+        assert isinstance(wrappeditems, list)
+        w_self.space = space
+        if space.config.objspace.std.withliststrategies:
+            w_self.strategy = get_strategy_from_list_objects(space, wrappeditems)
+        else:
+            w_self.strategy = space.fromcache(ObjectListStrategy)
+        w_self.init_from_list_w(wrappeditems)
+
+    @staticmethod
+    def from_storage_and_strategy(space, storage, strategy):
+        w_self = instantiate(W_ListObject)
+        w_self.space = space
+        w_self.strategy = strategy
+        w_self.lstorage = storage
+        if not space.config.objspace.std.withliststrategies:
+            w_self.switch_to_object_strategy()
+        return w_self
+
+    @staticmethod
+    def newlist_str(space, list_s):
+        strategy = space.fromcache(StringListStrategy)
+        storage = strategy.erase(list_s)
+        return W_ListObject.from_storage_and_strategy(space, storage, strategy)
 
     def __repr__(w_self):
         """ representation for debugging purposes """
-        return "%s(%s)" % (w_self.__class__.__name__, w_self.wrappeditems)
+        return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, w_self.lstorage._x)
 
     def unwrap(w_list, space):
-        items = [space.unwrap(w_item) for w_item in w_list.wrappeditems]# XXX generic mixed types unwrap
+        # for tests only!
+        items = [space.unwrap(w_item) for w_item in w_list.getitems()]
         return list(items)
 
+    def switch_to_object_strategy(self):
+        list_w = self.getitems()
+        self.strategy = self.space.fromcache(ObjectListStrategy)
+        # XXX this is quite indirect
+        self.init_from_list_w(list_w)
+
+    def _temporarily_as_objects(self):
+        if self.strategy is self.space.fromcache(ObjectListStrategy):
+            return self
+        list_w = self.getitems()
+        strategy = self.space.fromcache(ObjectListStrategy)
+        storage = strategy.erase(list_w)
+        w_objectlist = W_ListObject.from_storage_and_strategy(self.space, storage, strategy)
+        return w_objectlist
+
+    # ___________________________________________________
+
+    def init_from_list_w(self, list_w):
+        """Initializes listobject by iterating through the given list of
+        wrapped items, unwrapping them if neccessary and creating a
+        new erased object as storage"""
+        self.strategy.init_from_list_w(self, list_w)
+
+    def clone(self):
+        """Returns a clone by creating a new listobject
+        with the same strategy and a copy of the storage"""
+        return self.strategy.clone(self)
+
+    def copy_into(self, other):
+        """Used only when extending an EmptyList. Sets the EmptyLists
+        strategy and storage according to the other W_List"""
+        self.strategy.copy_into(self, other)
+
+    def contains(self, w_obj):
+        """Returns unwrapped boolean, saying wether w_obj exists
+        in the list."""
+        return self.strategy.contains(self, w_obj)
+
     def append(w_list, w_item):
-        w_list.wrappeditems.append(w_item)
+        """Appends the wrapped item to the end of the list."""
+        w_list.strategy.append(w_list, w_item)
+
+    def length(self):
+        return self.strategy.length(self)
+
+    def getitem(self, index):
+        """Returns the wrapped object that is found in the
+        list at the given index. The index must be unwrapped.
+        May raise IndexError."""
+        return self.strategy.getitem(self, index)
+
+    def getslice(self, start, stop, step, length):
+        """Returns a slice of the list defined by the arguments. Arguments must be
+        normalized (i.e. using normalize_simple_slice or W_Slice.indices4).
+        May raise IndexError."""
+        return self.strategy.getslice(self, start, stop, step, length)
+
+    def getitems(self):
+        """Returns a list of all items after wrapping them. The result can
+        share with the storage, if possible."""
+        return self.strategy.getitems(self)
+
+    def getitems_copy(self):
+        """Returns a copy of all items in the list. Same as getitems except for
+        ObjectListStrategy."""
+        return self.strategy.getitems_copy(self)
+
+    def getitems_str(self):
+        """ Return the items in the list as unwrapped strings. If the list does
+        not use the list strategy, return None. """
+        return self.strategy.getitems_str(self)
+    # ___________________________________________________
+
+
+    def mul(self, times):
+        """Returns a copy of the list, multiplied by times.
+        Argument must be unwrapped."""
+        return self.strategy.mul(self, times)
+
+    def inplace_mul(self, times):
+        """Alters the list by multiplying its content by times."""
+        self.strategy.inplace_mul(self, times)
+
+    def deleteslice(self, start, step, length):
+        """Deletes a slice from the list. Used in delitem and delslice.
+        Arguments must be normalized (see getslice)."""
+        self.strategy.deleteslice(self, start, step, length)
+
+    def pop(self, index):
+        """Pops an item from the list. Index must be normalized.
+        May raise IndexError."""
+        return self.strategy.pop(self, index)
+
+    def pop_end(self):
+        """ Pop the last element from the list."""
+        return self.strategy.pop_end(self)
+
+    def setitem(self, index, w_item):
+        """Inserts a wrapped item at the given (unwrapped) index.
+        May raise IndexError."""
+        self.strategy.setitem(self, index, w_item)
+
+    def setslice(self, start, step, slicelength, sequence_w):
+        """Sets the slice of the list from start to start+step*slicelength to
+        the sequence sequence_w.
+        Used by setslice and setitem."""
+        self.strategy.setslice(self, start, step, slicelength, sequence_w)
+
+    def insert(self, index, w_item):
+        """Inserts an item at the given position. Item must be wrapped,
+        index not."""
+        self.strategy.insert(self, index, w_item)
+
+    def extend(self, items_w):
+        """Appends the given list of wrapped items."""
+        self.strategy.extend(self, items_w)
+
+    def reverse(self):
+        """Reverses the list."""
+        self.strategy.reverse(self)
+
+    def sort(self, reverse):
+        """Sorts the list ascending or descending depending on
+        argument reverse. Argument must be unwrapped."""
+        self.strategy.sort(self, reverse)
 
 registerimplementation(W_ListObject)
 
 
+class ListStrategy(object):
+
+    def __init__(self, space):
+        self.space = space
+
+    def init_from_list_w(self, w_list, list_w):
+        raise NotImplementedError
+
+    def clone(self, w_list):
+        raise NotImplementedError
+
+    def copy_into(self, w_list, w_other):
+        raise NotImplementedError
+
+    def contains(self, w_list, w_obj):
+        # needs to be safe against eq_w() mutating the w_list behind our back
+        i = 0
+        while i < w_list.length(): # intentionally always calling len!
+            if self.space.eq_w(w_list.getitem(i), w_obj):
+                return True
+            i += 1
+        return False
+
+    def length(self, w_list):
+        raise NotImplementedError
+
+    def getitem(self, w_list, index):
+        raise NotImplementedError
+
+    def getslice(self, w_list, start, stop, step, length):
+        raise NotImplementedError
+
+    def getitems(self, w_list):
+        return self.getitems_copy(w_list)
+
+    def getitems_copy(self, w_list):
+        raise NotImplementedError
+
+    def getitems_str(self, w_list):
+        return None
+
+    def getstorage_copy(self, w_list):
+        raise NotImplementedError
+
+    def append(self, w_list, w_item):
+        raise NotImplementedError
+
+    def mul(self, w_list, times):
+        w_newlist = w_list.clone()
+        w_newlist.inplace_mul(times)
+        return w_newlist
+
+    def inplace_mul(self, w_list, times):
+        raise NotImplementedError
+
+    def deleteslice(self, w_list, start, step, slicelength):
+        raise NotImplementedError
+
+    def pop(self, w_list, index):
+        raise NotImplementedError
+
+    def pop_end(self, w_list):
+        return self.pop(w_list, self.length(w_list) - 1)
+
+    def setitem(self, w_list, index, w_item):
+        raise NotImplementedError
+
+    def setslice(self, w_list, start, step, slicelength, sequence_w):
+        raise NotImplementedError
+
+    def insert(self, w_list, index, w_item):
+        raise NotImplementedError
+
+    def extend(self, w_list, items_w):
+        raise NotImplementedError
+
+    def reverse(self, w_list):
+        raise NotImplementedError
+
+    def sort(self, w_list, reverse):
+        raise NotImplementedError
+
+class EmptyListStrategy(ListStrategy):
+    """EmptyListStrategy is used when a W_List withouth elements is created.
+    The storage is None. When items are added to the W_List a new RPython list
+    is created and the strategy and storage of the W_List are changed depending
+    to the added item.
+    W_Lists do not switch back to EmptyListStrategy when becoming empty again."""
+
+    def __init__(self, space):
+        ListStrategy.__init__(self, space)
+        # cache an empty list that is used whenever getitems is called (i.e. sorting)
+        self.cached_emptylist_w = []
+
+    def init_from_list_w(self, w_list, list_w):
+        assert len(list_w) == 0
+        w_list.lstorage = self.erase(None)
+
+    erase, unerase = rerased.new_erasing_pair("empty")
+    erase = staticmethod(erase)
+    unerase = staticmethod(unerase)
+
+    def clone(self, w_list):
+        return W_ListObject.from_storage_and_strategy(self.space, w_list.lstorage, self)
+
+    def copy_into(self, w_list, w_other):
+        pass
+
+    def contains(self, w_list, w_obj):
+        return False
+
+    def length(self, w_list):
+        return 0
+
+    def getitem(self, w_list, index):
+        raise IndexError
+
+    def getslice(self, w_list, start, stop, step, length):
+        # will never be called because the empty list case is already caught in
+        # getslice__List_ANY_ANY and getitem__List_Slice
+        return W_ListObject(self.space, self.cached_emptylist_w)
+
+    def getitems(self, w_list):
+        return self.cached_emptylist_w
+
+    def getitems_copy(self, w_list):
+        return []
+
+    def getstorage_copy(self, w_list):
+        return self.erase(None)
+
+    def switch_to_correct_strategy(self, w_list, w_item):
+        if is_W_IntObject(w_item):
+            strategy = self.space.fromcache(IntegerListStrategy)
+        elif is_W_StringObject(w_item):
+            strategy = self.space.fromcache(StringListStrategy)
+        else:
+            strategy = self.space.fromcache(ObjectListStrategy)
+
+        storage = strategy.get_empty_storage()
+        w_list.strategy = strategy
+        w_list.lstorage = storage
+
+    def append(self, w_list, w_item):
+        self.switch_to_correct_strategy(w_list, w_item)
+        w_list.append(w_item)
+
+    def inplace_mul(self, w_list, times):
+        return
+
+    def deleteslice(self, w_list, start, step, slicelength):
+        pass
+
+    def pop(self, w_list, index):
+        # will not be called because IndexError was already raised in
+        # list_pop__List_ANY
+        raise IndexError
+
+    def setitem(self, w_list, index, w_item):
+        raise IndexError
+
+    def setslice(self, w_list, start, step, slicelength, w_other):
+        strategy = w_other.strategy
+        storage = strategy.getstorage_copy(w_other)
+        w_list.strategy = strategy
+        w_list.lstorage = storage
+
+    def sort(self, w_list, reverse):
+        return
+
+    def insert(self, w_list, index, w_item):
+        assert index == 0
+        self.append(w_list, w_item)
+
+    def extend(self, w_list, w_other):
+        w_other.copy_into(w_list)
+
+    def reverse(self, w_list):
+        pass
+
+class RangeListStrategy(ListStrategy):
+    """RangeListStrategy is used when a list is created using the range method.
+    The storage is a tuple containing only three integers start, step and length
+    and elements are calculated based on these values.
+    On any operation destroying the range (inserting, appending non-ints)
+    the strategy is switched to IntegerListStrategy."""
+
+    def switch_to_integer_strategy(self, w_list):
+        items = self._getitems_range(w_list, False)
+        strategy = w_list.strategy = self.space.fromcache(IntegerListStrategy)
+        w_list.lstorage = strategy.erase(items)
+
+    def wrap(self, intval):
+        return self.space.wrap(intval)
+
+    def unwrap(self, w_int):
+        return self.space.int_w(w_int)
+
+    def init_from_list_w(self, w_list, list_w):
+        raise NotImplementedError
+
+    erase, unerase = rerased.new_erasing_pair("range")
+    erase = staticmethod(erase)
+    unerase = staticmethod(unerase)
+
+    def clone(self, w_list):
+        storage = w_list.lstorage # lstorage is tuple, no need to clone
+        w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, self)
+        return w_clone
+
+    def copy_into(self, w_list, w_other):
+        w_other.strategy = self
+        w_other.lstorage = w_list.lstorage
+
+    def contains(self, w_list, w_obj):
+        if is_W_IntObject(w_obj):
+            start, step, length = self.unerase(w_list.lstorage)
+            obj = self.unwrap(w_obj)
+            i = start
+            if step > 0 and start <= obj <= start + (length - 1) * step and (start - obj) % step == 0:
+                return True
+            elif step < 0 and start + (length -1) * step <= obj <= start and (start - obj) % step == 0:
+                return True
+            else:
+                return False
+        return ListStrategy.contains(self, w_list, w_obj)
+
+    def length(self, w_list):
+        return self.unerase(w_list.lstorage)[2]
+
+    def _getitem_unwrapped(self, w_list, i):
+        v = self.unerase(w_list.lstorage)
+        start = v[0]
+        step = v[1]
+        length = v[2]
+        if i < 0:
+            i += length
+            if i < 0:
+                raise IndexError
+        elif i >= length:
+            raise IndexError
+        return start + i * step
+
+    def getitem(self, w_list, i):
+        return self.wrap(self._getitem_unwrapped(w_list, i))
+
+    def getitems_copy(self, w_list):
+        return self._getitems_range(w_list, True)
+
+    def getstorage_copy(self, w_list):
+        # tuple is unmutable
+        return w_list.lstorage
+
+
+    @specialize.arg(2)
+    def _getitems_range(self, w_list, wrap_items):
+        l = self.unerase(w_list.lstorage)
+        start = l[0]
+        step = l[1]
+        length  = l[2]
+        if wrap_items:
+            r = [None] * length
+        else:
+            r = [0] * length
+        i = start
+        n = 0
+        while n < length:
+            if wrap_items:
+                r[n] = self.wrap(i)
+            else:
+                r[n] = i
+            i += step
+            n += 1
+
+        return r
+
+    def getslice(self, w_list, start, stop, step, length):
+        v = self.unerase(w_list.lstorage)
+        old_start = v[0]
+        old_step = v[1]
+        old_length = v[2]
+
+        new_start = self._getitem_unwrapped(w_list, start)
+        new_step = old_step * step
+        return make_range_list(self.space, new_start, new_step, length)
+
+    def append(self, w_list, w_item):
+        if is_W_IntObject(w_item):
+            l = self.unerase(w_list.lstorage)
+            step = l[1]
+            last_in_range = self._getitem_unwrapped(w_list, -1)
+            if self.unwrap(w_item) - step == last_in_range:
+                new = self.erase((l[0],l[1],l[2]+1))
+                w_list.lstorage = new
+                return
+
+            self.switch_to_integer_strategy(w_list)
+        else:
+            w_list.switch_to_object_strategy()
+        w_list.append(w_item)
+
+    def inplace_mul(self, w_list, times):
+        self.switch_to_integer_strategy(w_list)
+        w_list.inplace_mul(times)
+
+    def deleteslice(self, w_list, start, step, slicelength):
+        self.switch_to_integer_strategy(w_list)
+        w_list.deleteslice(start, step, slicelength)
+
+    def pop_end(self, w_list):
+        start, step, length = self.unerase(w_list.lstorage)
+        w_result = self.wrap(start + (length - 1) * step)
+        new = self.erase((start, step, length - 1))
+        w_list.lstorage = new
+        return w_result
+
+    def pop(self, w_list, index):
+        l = self.unerase(w_list.lstorage)
+        start = l[0]
+        step = l[1]
+        length = l[2]
+        if index == 0:
+            w_result = self.wrap(start)
+            new = self.erase((start + step, step, length - 1))
+            w_list.lstorage = new
+            return w_result
+        elif index == length - 1:
+            return self.pop_end(w_list)
+        else:
+            self.switch_to_integer_strategy(w_list)
+            return w_list.pop(index)
+
+    def setitem(self, w_list, index, w_item):
+        self.switch_to_integer_strategy(w_list)
+        w_list.setitem(index, w_item)
+
+    def setslice(self, w_list, start, step, slicelength, sequence_w):
+        self.switch_to_integer_strategy(w_list)
+        w_list.setslice(start, step, slicelength, sequence_w)
+
+    def sort(self, w_list, reverse):
+        start, step, length = self.unerase(w_list.lstorage)
+        if step > 0 and reverse or step < 0 and not reverse:
+            start = start + step * (length - 1)
+            step = step * (-1)
+        else:
+            return
+        w_list.lstorage = self.erase((start, step, length))
+
+    def insert(self, w_list, index, w_item):
+        self.switch_to_integer_strategy(w_list)
+        w_list.insert(index, w_item)
+
+    def extend(self, w_list, items_w):
+        self.switch_to_integer_strategy(w_list)
+        w_list.extend(items_w)
+
+    def reverse(self, w_list):
+        v = self.unerase(w_list.lstorage)
+        last = self._getitem_unwrapped(w_list, -1)
+        length = v[2]
+        skip = v[1]
+        new = self.erase((last, -skip, length))
+        w_list.lstorage = new
+
+class AbstractUnwrappedStrategy(object):
+    _mixin_ = True
+
+    def wrap(self, unwrapped):
+        raise NotImplementedError
+
+    def unwrap(self, wrapped):
+        raise NotImplementedError
+
+    @staticmethod
+    def unerase(storage):
+        raise NotImplementedError("abstract base class")
+
+    @staticmethod
+    def erase(obj):
+        raise NotImplementedError("abstract base class")
+
+    def is_correct_type(self, w_obj):
+        raise NotImplementedError("abstract base class")
+
+    def list_is_correct_type(self, w_list):
+        raise NotImplementedError("abstract base class")
+
+    @jit.look_inside_iff(lambda space, w_list, list_w:
+        jit.isconstant(len(list_w)) and len(list_w) < UNROLL_CUTOFF)
+    def init_from_list_w(self, w_list, list_w):
+        l = [self.unwrap(w_item) for w_item in list_w]
+        w_list.lstorage = self.erase(l)
+
+    def get_empty_storage(self):
+        return self.erase([])
+
+    def clone(self, w_list):
+        l = self.unerase(w_list.lstorage)
+        storage = self.erase(l[:])
+        w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, self)
+        return w_clone
+
+    def copy_into(self, w_list, w_other):
+        w_other.strategy = self
+        items = self.unerase(w_list.lstorage)[:]
+        w_other.lstorage = self.erase(items)
+
+    def contains(self, w_list, w_obj):
+        if self.is_correct_type(w_obj):
+            obj = self.unwrap(w_obj)
+            l = self.unerase(w_list.lstorage)
+            for i in l:
+                if i == obj:
+                    return True
+        return ListStrategy.contains(self, w_list, w_obj)
+
+    def length(self, w_list):
+        return len(self.unerase(w_list.lstorage))
+
+    def getitem(self, w_list, index):
+        l = self.unerase(w_list.lstorage)
+        try:
+            r = l[index]
+        except IndexError: # make RPython raise the exception
+            raise
+        return self.wrap(r)
+
+    @jit.look_inside_iff(lambda self, w_list:
+            jit.isconstant(w_list.length()) and w_list.length() < UNROLL_CUTOFF)
+    def getitems_copy(self, w_list):
+        return [self.wrap(item) for item in self.unerase(w_list.lstorage)]
+
+    def getstorage_copy(self, w_list):
+        items = self.unerase(w_list.lstorage)[:]
+        return self.erase(items)
+
+
+    def getslice(self, w_list, start, stop, step, length):
+        if step == 1 and 0 <= start <= stop:
+            l = self.unerase(w_list.lstorage)
+            assert start >= 0
+            assert stop >= 0
+            sublist = l[start:stop]
+            storage = self.erase(sublist)
+            return W_ListObject.from_storage_and_strategy(self.space, storage, self)
+        else:
+            subitems_w = [self._none_value] * length
+            l = self.unerase(w_list.lstorage)
+            for i in range(length):
+                try:
+                    subitems_w[i] = l[start]
+                    start += step
+                except IndexError:
+                    raise
+            storage = self.erase(subitems_w)
+            return W_ListObject.from_storage_and_strategy(self.space, storage, self)
+
+    def append(self,  w_list, w_item):
+
+        if self.is_correct_type(w_item):
+            self.unerase(w_list.lstorage).append(self.unwrap(w_item))
+            return
+
+        w_list.switch_to_object_strategy()
+        w_list.append(w_item)
+
+    def insert(self, w_list, index, w_item):
+        l = self.unerase(w_list.lstorage)
+
+        if self.is_correct_type(w_item):
+            l.insert(index, self.unwrap(w_item))
+            return
+
+        w_list.switch_to_object_strategy()
+        w_list.insert(index, w_item)
+
+    def extend(self, w_list, w_other):
+        l = self.unerase(w_list.lstorage)
+        if self.list_is_correct_type(w_other):
+            l += self.unerase(w_other.lstorage)
+            return
+        elif w_other.strategy is self.space.fromcache(EmptyListStrategy):
+            return
+
+        w_other = w_other._temporarily_as_objects()
+        w_list.switch_to_object_strategy()
+        w_list.extend(w_other)
+
+    def setitem(self, w_list, index, w_item):
+        l = self.unerase(w_list.lstorage)
+
+        if self.is_correct_type(w_item):
+            try:
+                l[index] = self.unwrap(w_item)
+            except IndexError:
+                raise
+            return
+
+        w_list.switch_to_object_strategy()
+        w_list.setitem(index, w_item)
+
+    def setslice(self, w_list, start, step, slicelength, w_other):
+        assert slicelength >= 0
+        items = self.unerase(w_list.lstorage)
+
+        if self is self.space.fromcache(ObjectListStrategy):
+            w_other = w_other._temporarily_as_objects()
+        elif (not self.list_is_correct_type(w_other) and
+               w_other.length() != 0):
+            w_list.switch_to_object_strategy()
+            w_other_as_object = w_other._temporarily_as_objects()
+            assert w_other_as_object.strategy is self.space.fromcache(ObjectListStrategy)
+            w_list.setslice(start, step, slicelength, w_other_as_object)
+            return
+
+        oldsize = len(items)
+        len2 = w_other.length()
+        if step == 1:  # Support list resizing for non-extended slices
+            delta = slicelength - len2
+            if delta < 0:
+                delta = -delta
+                newsize = oldsize + delta
+                # XXX support this in rlist!
+                items += [self._none_value] * delta
+                lim = start+len2
+                i = newsize - 1
+                while i >= lim:
+                    items[i] = items[i-delta]
+                    i -= 1
+            elif start >= 0:
+                del items[start:start+delta]
+            else:
+                assert delta==0   # start<0 is only possible with slicelength==0
+        elif len2 != slicelength:  # No resize for extended slices
+            raise operationerrfmt(self.space.w_ValueError, "attempt to "
+                  "assign sequence of size %d to extended slice of size %d",
+                  len2, slicelength)
+
+        if w_other.strategy is self.space.fromcache(EmptyListStrategy):
+            other_items = []
+        else:
+            # at this point both w_list and w_other have the same type, so
+            # self.unerase is valid for both of them
+            other_items = self.unerase(w_other.lstorage)
+        if other_items is items:
+            if step > 0:
+                # Always copy starting from the right to avoid
+                # having to make a shallow copy in the case where
+                # the source and destination lists are the same list.
+                i = len2 - 1
+                start += i*step
+                while i >= 0:
+                    items[start] = other_items[i]
+                    start -= step
+                    i -= 1
+                return
+            else:
+                # Make a shallow copy to more easily handle the reversal case
+                w_list.reverse()
+                return
+                #other_items = list(other_items)
+        for i in range(len2):
+            items[start] = other_items[i]
+            start += step
+
+    def deleteslice(self, w_list, start, step, slicelength):
+        items = self.unerase(w_list.lstorage)
+        if slicelength==0:
+            return
+
+        if step < 0:
+            start = start + step * (slicelength-1)
+            step = -step
+
+        if step == 1:
+            assert start >= 0
+            assert slicelength >= 0
+            del items[start:start+slicelength]
+        else:
+            n = len(items)
+            i = start
+
+            for discard in range(1, slicelength):
+                j = i+1
+                i += step
+                while j < i:
+                    items[j-discard] = items[j]
+                    j += 1
+
+            j = i+1
+            while j < n:
+                items[j-slicelength] = items[j]
+                j += 1
+            start = n - slicelength
+            assert start >= 0 # annotator hint
+            del items[start:]
+
+    def pop_end(self, w_list):
+        l = self.unerase(w_list.lstorage)
+        return self.wrap(l.pop())
+
+    def pop(self, w_list, index):
+        l = self.unerase(w_list.lstorage)
+        # not sure if RPython raises IndexError on pop
+        # so check again here
+        if index < 0:
+            raise IndexError
+        try:
+            item = l.pop(index)
+        except IndexError:
+            raise
+
+        w_item = self.wrap(item)
+        return w_item
+
+    def inplace_mul(self, w_list, times):
+        l = self.unerase(w_list.lstorage)
+        l *= times
+
+    def reverse(self, w_list):
+        self.unerase(w_list.lstorage).reverse()
+
+class ObjectListStrategy(AbstractUnwrappedStrategy, ListStrategy):
+    _none_value = None
+
+    def unwrap(self, w_obj):
+        return w_obj
+
+    def wrap(self, item):
+        return item
+
+    erase, unerase = rerased.new_erasing_pair("object")
+    erase = staticmethod(erase)
+    unerase = staticmethod(unerase)
+
+    def is_correct_type(self, w_obj):
+        return True
+
+    def list_is_correct_type(self, w_list):
+        return w_list.strategy is self.space.fromcache(ObjectListStrategy)
+
+    def init_from_list_w(self, w_list, list_w):
+        w_list.lstorage = self.erase(list_w)
+
+    def contains(self, w_list, w_obj):
+        return ListStrategy.contains(self, w_list, w_obj)
+
+    def getitems(self, w_list):
+        return self.unerase(w_list.lstorage)
+
+class IntegerListStrategy(AbstractUnwrappedStrategy, ListStrategy):
+    _none_value = 0
+
+    def wrap(self, intval):
+        return self.space.wrap(intval)
+
+    def unwrap(self, w_int):
+        return self.space.int_w(w_int)
+
+    erase, unerase = rerased.new_erasing_pair("integer")
+    erase = staticmethod(erase)
+    unerase = staticmethod(unerase)
+
+    def is_correct_type(self, w_obj):
+        return is_W_IntObject(w_obj)
+
+    def list_is_correct_type(self, w_list):
+        return w_list.strategy is self.space.fromcache(IntegerListStrategy)
+
+    def sort(self, w_list, reverse):
+        l = self.unerase(w_list.lstorage)
+        sorter = IntSort(l, len(l))
+        sorter.sort()
+        if reverse:
+            l.reverse()
+
+class StringListStrategy(AbstractUnwrappedStrategy, ListStrategy):
+    _none_value = None
+
+    def wrap(self, stringval):
+        return self.space.wrap(stringval)
+
+    def unwrap(self, w_string):
+        return self.space.str_w(w_string)
+
+    erase, unerase = rerased.new_erasing_pair("string")
+    erase = staticmethod(erase)
+    unerase = staticmethod(unerase)
+
+    def is_correct_type(self, w_obj):
+        return is_W_StringObject(w_obj)
+
+    def list_is_correct_type(self, w_list):
+        return w_list.strategy is self.space.fromcache(StringListStrategy)
+
+    def sort(self, w_list, reverse):
+        l = self.unerase(w_list.lstorage)
+        sorter = StringSort(l, len(l))
+        sorter.sort()
+        if reverse:
+            l.reverse()
+
+    def getitems_str(self, w_list):
+        return self.unerase(w_list.lstorage)
+
+# _______________________________________________________
+
 init_signature = Signature(['sequence'], None, None)
 init_defaults = [None]
 
@@ -42,25 +944,24 @@
     # this is on the silly side
     w_iterable, = __args__.parse_obj(
             None, 'list', init_signature, init_defaults)
-    items_w = w_list.wrappeditems
-    del items_w[:]
+    w_list.__init__(space, [])
     if w_iterable is not None:
         # unfortunately this is duplicating space.unpackiterable to avoid
         # assigning a new RPython list to 'wrappeditems', which defeats the
         # W_FastListIterObject optimization.
         if isinstance(w_iterable, W_ListObject):
-            items_w.extend(w_iterable.wrappeditems)
+            w_list.extend(w_iterable)
         elif isinstance(w_iterable, W_TupleObject):
-            items_w.extend(w_iterable.wrappeditems)
+            w_list.extend(W_ListObject(space, w_iterable.wrappeditems[:]))
         else:
-            _init_from_iterable(space, items_w, w_iterable)
+            _init_from_iterable(space, w_list, w_iterable)
 
-def _init_from_iterable(space, items_w, w_iterable):
+def _init_from_iterable(space, w_list, w_iterable):
     # in its own function to make the JIT look into init__List
     # xxx special hack for speed
     from pypy.interpreter.generator import GeneratorIterator
     if isinstance(w_iterable, GeneratorIterator):
-        w_iterable.unpack_into(items_w)
+        w_iterable.unpack_into_w(w_list)
         return
     # /xxx
     w_iterator = space.iter(w_iterable)
@@ -71,70 +972,65 @@
             if not e.match(space, space.w_StopIteration):
                 raise
             break  # done
-        items_w.append(w_item)
+        w_list.append(w_item)
 
 def len__List(space, w_list):
-    result = len(w_list.wrappeditems)
+    result = w_list.length()
     return wrapint(space, result)
 
 def getitem__List_ANY(space, w_list, w_index):
     try:
-        return w_list.wrappeditems[get_list_index(space, w_index)]
+        return w_list.getitem(get_list_index(space, w_index))
     except IndexError:
         raise OperationError(space.w_IndexError,
                              space.wrap("list index out of range"))
 
 def getitem__List_Slice(space, w_list, w_slice):
     # XXX consider to extend rlist's functionality?
-    length = len(w_list.wrappeditems)
+    length = w_list.length()
     start, stop, step, slicelength = w_slice.indices4(space, length)
     assert slicelength >= 0
-    if step == 1 and 0 <= start <= stop:
-        return W_ListObject(w_list.wrappeditems[start:stop])
-    w_res = W_ListObject([None] * slicelength)
-    items_w = w_list.wrappeditems
-    subitems_w = w_res.wrappeditems
-    for i in range(slicelength):
-        subitems_w[i] = items_w[start]
-        start += step
-    return w_res
+    if slicelength == 0:
+        return make_empty_list(space)
+    return w_list.getslice(start, stop, step, slicelength)
 
 def getslice__List_ANY_ANY(space, w_list, w_start, w_stop):
-    length = len(w_list.wrappeditems)
-    start, stop = normalize_simple_slice(space, length, w_start, w_stop)
-    return W_ListObject(w_list.wrappeditems[start:stop])
-
-def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_sequence):
-    length = len(w_list.wrappeditems)
+    length = w_list.length()
     start, stop = normalize_simple_slice(space, length, w_start, w_stop)
 
-    sequence2 = space.listview(w_sequence)
-    items = w_list.wrappeditems
-    _setitem_slice_helper(space, items, start, 1, stop-start, sequence2,
-                          empty_elem=None)
+    slicelength = stop - start
+    if slicelength == 0:
+        return make_empty_list(space)
+    return w_list.getslice(start, stop, 1, stop - start)
+
+def setslice__List_ANY_ANY_List(space, w_list, w_start, w_stop, w_other):
+    length = w_list.length()
+    start, stop = normalize_simple_slice(space, length, w_start, w_stop)
+    w_list.setslice(start, 1, stop-start, w_other)
+
+def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_iterable):
+    length = w_list.length()
+    start, stop = normalize_simple_slice(space, length, w_start, w_stop)
+    sequence_w = space.listview(w_iterable)
+    w_other = W_ListObject(space, sequence_w)
+    w_list.setslice(start, 1, stop-start, w_other)
 
 def delslice__List_ANY_ANY(space, w_list, w_start, w_stop):
-    length = len(w_list.wrappeditems)
+    length = w_list.length()
     start, stop = normalize_simple_slice(space, length, w_start, w_stop)
-    _delitem_slice_helper(space, w_list.wrappeditems, start, 1, stop-start)
+    w_list.deleteslice(start, 1, stop-start)
 
 def contains__List_ANY(space, w_list, w_obj):
-    # needs to be safe against eq_w() mutating the w_list behind our back
-    i = 0
-    items_w = w_list.wrappeditems
-    while i < len(items_w): # intentionally always calling len!
-        if space.eq_w(items_w[i], w_obj):
-            return space.w_True
-        i += 1
-    return space.w_False
+    return space.wrap(w_list.contains(w_obj))
 
 def iter__List(space, w_list):
     from pypy.objspace.std import iterobject
-    return iterobject.W_FastListIterObject(w_list, w_list.wrappeditems)
+    return iterobject.W_FastListIterObject(w_list)
 
 def add__List_List(space, w_list1, w_list2):
-    return W_ListObject(w_list1.wrappeditems + w_list2.wrappeditems)
-
+    w_clone = w_list1.clone()
+    w_clone.extend(w_list2)
+    return w_clone
 
 def inplace_add__List_ANY(space, w_list1, w_iterable2):
     try:
@@ -156,7 +1052,7 @@
         if e.match(space, space.w_TypeError):
             raise FailedToImplement
         raise
-    return W_ListObject(w_list.wrappeditems * times)
+    return w_list.mul(times)
 
 def mul__List_ANY(space, w_list, w_times):
     return mul_list_times(space, w_list, w_times)
@@ -171,63 +1067,65 @@
         if e.match(space, space.w_TypeError):
             raise FailedToImplement
         raise
-    w_list.wrappeditems *= times
+    w_list.inplace_mul(times)
     return w_list
 
 def eq__List_List(space, w_list1, w_list2):
     # needs to be safe against eq_w() mutating the w_lists behind our back
-    items1_w = w_list1.wrappeditems
-    items2_w = w_list2.wrappeditems
-    return equal_wrappeditems(space, items1_w, items2_w)
+    if w_list1.length() != w_list2.length():
+        return space.w_False
 
-def equal_wrappeditems(space, items1_w, items2_w):
-    if len(items1_w) != len(items2_w):
-        return space.w_False
+    # XXX in theory, this can be implemented more efficiently as well. let's
+    # not care for now
     i = 0
-    while i < len(items1_w) and i < len(items2_w):
-        if not space.eq_w(items1_w[i], items2_w[i]):
+    while i < w_list1.length() and i < w_list2.length():
+        if not space.eq_w(w_list1.getitem(i), w_list2.getitem(i)):
             return space.w_False
         i += 1
     return space.w_True
 
-def lessthan_unwrappeditems(space, items1_w, items2_w):
+def lessthan_unwrappeditems(space, w_list1, w_list2):
     # needs to be safe against eq_w() mutating the w_lists behind our back
     # Search for the first index where items are different
     i = 0
-    while i < len(items1_w) and i < len(items2_w):
-        w_item1 = items1_w[i]
-        w_item2 = items2_w[i]
+    # XXX in theory, this can be implemented more efficiently as well. let's
+    # not care for now
+    while i < w_list1.length() and i < w_list2.length():
+        w_item1 = w_list1.getitem(i)
+        w_item2 = w_list2.getitem(i)
         if not space.eq_w(w_item1, w_item2):
             return space.lt(w_item1, w_item2)
         i += 1
     # No more items to compare -- compare sizes
-    return space.newbool(len(items1_w) < len(items2_w))
+    return space.newbool(w_list1.length() < w_list2.length())
 
-def greaterthan_unwrappeditems(space, items1_w, items2_w):
+def greaterthan_unwrappeditems(space, w_list1, w_list2):
     # needs to be safe against eq_w() mutating the w_lists behind our back
     # Search for the first index where items are different
     i = 0
-    while i < len(items1_w) and i < len(items2_w):
-        w_item1 = items1_w[i]
-        w_item2 = items2_w[i]
+    # XXX in theory, this can be implemented more efficiently as well. let's
+    # not care for now
+    while i < w_list1.length() and i < w_list2.length():
+        w_item1 = w_list1.getitem(i)
+        w_item2 = w_list2.getitem(i)
         if not space.eq_w(w_item1, w_item2):
             return space.gt(w_item1, w_item2)
         i += 1
     # No more items to compare -- compare sizes
-    return space.newbool(len(items1_w) > len(items2_w))
+    return space.newbool(w_list1.length() > w_list2.length())
 
 def lt__List_List(space, w_list1, w_list2):
-    return lessthan_unwrappeditems(space, w_list1.wrappeditems,
-        w_list2.wrappeditems)
+    return lessthan_unwrappeditems(space, w_list1, w_list2)
 
 def gt__List_List(space, w_list1, w_list2):
-    return greaterthan_unwrappeditems(space, w_list1.wrappeditems,
-        w_list2.wrappeditems)
+    return greaterthan_unwrappeditems(space, w_list1, w_list2)
 
 def delitem__List_ANY(space, w_list, w_idx):
     idx = get_list_index(space, w_idx)
+    if idx < 0:
+        idx += w_list.length()
     try:
-        del w_list.wrappeditems[idx]
+        w_list.pop(idx)
     except IndexError:
         raise OperationError(space.w_IndexError,
                              space.wrap("list deletion index out of range"))
@@ -235,103 +1133,29 @@
 
 
 def delitem__List_Slice(space, w_list, w_slice):
-    start, stop, step, slicelength = w_slice.indices4(space,
-                                                      len(w_list.wrappeditems))
-    _delitem_slice_helper(space, w_list.wrappeditems, start, step, slicelength)
-
-def _delitem_slice_helper(space, items, start, step, slicelength):
-    if slicelength==0:
-        return
-
-    if step < 0:
-        start = start + step * (slicelength-1)
-        step = -step
-
-    if step == 1:
-        assert start >= 0
-        assert slicelength >= 0
-        del items[start:start+slicelength]
-    else:
-        n = len(items)
-        i = start
-
-        for discard in range(1, slicelength):
-            j = i+1
-            i += step
-            while j < i:
-                items[j-discard] = items[j]
-                j += 1
-
-        j = i+1
-        while j < n:
-            items[j-slicelength] = items[j]
-            j += 1
-        start = n - slicelength
-        assert start >= 0 # annotator hint
-        del items[start:]
+    start, stop, step, slicelength = w_slice.indices4(space, w_list.length())
+    w_list.deleteslice(start, step, slicelength)
 
 def setitem__List_ANY_ANY(space, w_list, w_index, w_any):
     idx = get_list_index(space, w_index)
     try:
-        w_list.wrappeditems[idx] = w_any
+        w_list.setitem(idx, w_any)
     except IndexError:
         raise OperationError(space.w_IndexError,
                              space.wrap("list index out of range"))
     return space.w_None
 
+def setitem__List_Slice_List(space, w_list, w_slice, w_other):
+    oldsize = w_list.length()
+    start, stop, step, slicelength = w_slice.indices4(space, oldsize)
+    w_list.setslice(start, step, slicelength, w_other)
+
 def setitem__List_Slice_ANY(space, w_list, w_slice, w_iterable):
-    oldsize = len(w_list.wrappeditems)
+    oldsize = w_list.length()
     start, stop, step, slicelength = w_slice.indices4(space, oldsize)
-
-    sequence2 = space.listview(w_iterable)
-    items = w_list.wrappeditems
-    _setitem_slice_helper(space, items, start, step, slicelength, sequence2,
-                          empty_elem=None)
-
-def _setitem_slice_helper(space, items, start, step, slicelength, sequence2,
-                          empty_elem):
-    assert slicelength >= 0
-    oldsize = len(items)
-    len2 = len(sequence2)
-    if step == 1:  # Support list resizing for non-extended slices
-        delta = slicelength - len2
-        if delta < 0:
-            delta = -delta
-            newsize = oldsize + delta
-            # XXX support this in rlist!
-            items += [empty_elem] * delta
-            lim = start+len2
-            i = newsize - 1
-            while i >= lim:
-                items[i] = items[i-delta]
-                i -= 1
-        elif start >= 0:
-            del items[start:start+delta]
-        else:
-            assert delta==0   # start<0 is only possible with slicelength==0
-    elif len2 != slicelength:  # No resize for extended slices
-        raise operationerrfmt(space.w_ValueError, "attempt to "
-              "assign sequence of size %d to extended slice of size %d",
-              len2, slicelength)
-
-    if sequence2 is items:
-        if step > 0:
-            # Always copy starting from the right to avoid
-            # having to make a shallow copy in the case where
-            # the source and destination lists are the same list.
-            i = len2 - 1
-            start += i*step
-            while i >= 0:
-                items[start] = sequence2[i]
-                start -= step
-                i -= 1
-            return
-        else:
-            # Make a shallow copy to more easily handle the reversal case
-            sequence2 = list(sequence2)
-    for i in range(len2):
-        items[start] = sequence2[i]
-        start += step


More information about the pypy-commit mailing list