[pypy-commit] pypy py3k-fix-strategies: merge py3k

pjenvey noreply at buildbot.pypy.org
Fri Apr 18 02:43:06 CEST 2014


Author: Philip Jenvey <pjenvey at underboss.org>
Branch: py3k-fix-strategies
Changeset: r70733:a98806ecc708
Date: 2014-04-17 16:32 -0700
http://bitbucket.org/pypy/pypy/changeset/a98806ecc708/

Log:	merge py3k

diff too long, truncating to 2000 out of 2524 lines

diff --git a/lib-python/3/sre_compile.py b/lib-python/3/sre_compile.py
--- a/lib-python/3/sre_compile.py
+++ b/lib-python/3/sre_compile.py
@@ -13,7 +13,6 @@
 import _sre, sys
 import sre_parse
 from sre_constants import *
-from _sre import MAXREPEAT
 
 assert _sre.MAGIC == MAGIC, "SRE module mismatch"
 
@@ -356,8 +355,6 @@
 def _simple(av):
     # check if av is a "simple" operator
     lo, hi = av[2].getwidth()
-    if lo == 0 and hi == MAXREPEAT:
-        raise error("nothing to repeat")
     return lo == hi == 1 and av[2][0][0] != SUBPATTERN
 
 def _compile_info(code, pattern, flags):
diff --git a/pypy/config/test/test_pypyoption.py b/pypy/config/test/test_pypyoption.py
--- a/pypy/config/test/test_pypyoption.py
+++ b/pypy/config/test/test_pypyoption.py
@@ -12,9 +12,9 @@
     assert conf.objspace.usemodules.gc
 
     conf.objspace.std.withmapdict = True
-    assert conf.objspace.std.withmethodcache
+    assert conf.objspace.std.withtypeversion
     conf = get_pypy_config()
-    conf.objspace.std.withmethodcache = False
+    conf.objspace.std.withtypeversion = False
     py.test.raises(ConfigError, "conf.objspace.std.withmapdict = True")
 
 def test_conflicting_gcrootfinder():
diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -318,7 +318,7 @@
 
 To read more about the RPython limitations read the `RPython description`_.
 
-.. _`RPython description`: coding-guide.html#restricted-python
+.. _`RPython description`: coding-guide.html#rpython-definition
 
 ---------------------------------------------------------------
 Does RPython have anything to do with Zope's Restricted Python?
diff --git a/pypy/doc/index-report.rst b/pypy/doc/index-report.rst
--- a/pypy/doc/index-report.rst
+++ b/pypy/doc/index-report.rst
@@ -92,7 +92,9 @@
 `D07.1 Massive Parallelism and Translation Aspects`_ is a report about
 PyPy's optimization efforts, garbage collectors and massive parallelism
 (stackless) features.  This report refers to the paper `PyPy's approach
-to virtual machine construction`_. *(2007-02-28)*
+to virtual machine construction`_.  Extends the content previously
+available in the document "Memory management and threading models as
+translation aspects -- solutions and challenges".  *(2007-02-28)*
 
 
 
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -133,4 +133,10 @@
 
 .. branch: ast-issue1673
 fix ast classes __dict__ are always empty problem and fix the ast deepcopy issue when 
-there is missing field
\ No newline at end of file
+there is missing field
+
+.. branch: issue1514
+Fix issues with reimporting builtin modules
+
+.. branch: numpypy-nditer
+Implement the core of nditer, without many of the fancy flags (external_loop, buffered)
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -339,6 +339,9 @@
         return 'internal subclass of %s' % (Class.__name__,)
 wrappable_class_name._annspecialcase_ = 'specialize:memo'
 
+class CannotHaveLock(Exception):
+    """Raised by space.allocate_lock() if we're translating."""
+
 # ____________________________________________________________
 
 class ObjSpace(object):
@@ -442,10 +445,11 @@
 
         return name
 
-    def getbuiltinmodule(self, name, force_init=False):
+    def getbuiltinmodule(self, name, force_init=False, reuse=True):
         w_name = self.wrap(name)
         w_modules = self.sys.get('modules')
         if not force_init:
+            assert reuse
             try:
                 return self.getitem(w_modules, w_name)
             except OperationError, e:
@@ -460,15 +464,25 @@
             raise oefmt(self.w_SystemError,
                         "getbuiltinmodule() called with non-builtin module %s",
                         name)
+
+        # Add the module to sys.modules and initialize the module. The
+        # order is important to avoid recursions.
+        from pypy.interpreter.module import Module
+        if isinstance(w_mod, Module):
+            if not reuse and w_mod.startup_called:
+                # create a copy of the module.  (see issue1514) eventlet
+                # patcher relies on this behaviour.
+                w_mod2 = self.wrap(Module(self, w_name))
+                self.setitem(w_modules, w_name, w_mod2)
+                w_mod.getdict(self)  # unlazy w_initialdict
+                self.call_method(w_mod2.getdict(self), 'update',
+                                 w_mod.w_initialdict)
+                return w_mod2
+            self.setitem(w_modules, w_name, w_mod)
+            w_mod.init(self)
         else:
-            # Initialize the module
-            from pypy.interpreter.module import Module
-            if isinstance(w_mod, Module):
-                w_mod.init(self)
-
-            # Add the module to sys.modules
             self.setitem(w_modules, w_name, w_mod)
-            return w_mod
+        return w_mod
 
     def get_builtinmodule_to_install(self):
         """NOT_RPYTHON"""
@@ -676,6 +690,11 @@
 
     def __allocate_lock(self):
         from rpython.rlib.rthread import allocate_lock, error
+        # hack: we can't have prebuilt locks if we're translating.
+        # In this special situation we should just not lock at all
+        # (translation is not multithreaded anyway).
+        if not we_are_translated() and self.config.translating:
+            raise CannotHaveLock()
         try:
             return allocate_lock()
         except error:
diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py
--- a/pypy/interpreter/mixedmodule.py
+++ b/pypy/interpreter/mixedmodule.py
@@ -14,6 +14,7 @@
     # after startup().
     w_initialdict = None
     lazy = False
+    submodule_name = None
 
     def __init__(self, space, w_name):
         """ NOT_RPYTHON """
@@ -31,6 +32,8 @@
             space = self.space
             name = space.unwrap(self.w_name)
             for sub_name, module_cls in self.submodules.iteritems():
+                if module_cls.submodule_name is None:
+                    module_cls.submodule_name = sub_name
                 module_name = space.wrap("%s.%s" % (name, sub_name))
                 m = module_cls(space, module_name)
                 m.install()
@@ -134,6 +137,8 @@
             cls.loaders = loaders = {}
             pkgroot = cls.__module__
             appname = cls.get_applevel_name()
+            if cls.submodule_name is not None:
+                appname += '.%s' % (cls.submodule_name,)
             for name, spec in cls.interpleveldefs.items():
                 loaders[name] = getinterpevalloader(pkgroot, spec)
             for name, spec in cls.appleveldefs.items():
diff --git a/pypy/module/__pypy__/app_signal.py b/pypy/module/__pypy__/app_signal.py
--- a/pypy/module/__pypy__/app_signal.py
+++ b/pypy/module/__pypy__/app_signal.py
@@ -1,4 +1,9 @@
-import __pypy__.thread
+from . import thread
+# ^^ relative import of __pypy__.thread.  Note that some tests depend on
+# this (test_enable_signals in test_signal.py) to work properly,
+# otherwise they get caught in some deadlock waiting for the import
+# lock...
+
 
 class SignalsEnabled(object):
     '''A context manager to use in non-main threads:
@@ -8,7 +13,7 @@
 that is within a "with signals_enabled:".  This other thread should be
 ready to handle unexpected exceptions that the signal handler might
 raise --- notably KeyboardInterrupt.'''
-    __enter__ = __pypy__.thread._signals_enter
-    __exit__  = __pypy__.thread._signals_exit
+    __enter__ = thread._signals_enter
+    __exit__  = thread._signals_exit
 
 signals_enabled = SignalsEnabled()
diff --git a/pypy/module/__pypy__/test/test_signal.py b/pypy/module/__pypy__/test/test_signal.py
--- a/pypy/module/__pypy__/test/test_signal.py
+++ b/pypy/module/__pypy__/test/test_signal.py
@@ -8,6 +8,7 @@
 
     def test_signal(self):
         from __pypy__ import thread
+        assert type(thread.signals_enabled).__module__ == '__pypy__.thread'
         with thread.signals_enabled:
             pass
         # assert did not crash
diff --git a/pypy/module/_multibytecodec/c_codecs.py b/pypy/module/_multibytecodec/c_codecs.py
--- a/pypy/module/_multibytecodec/c_codecs.py
+++ b/pypy/module/_multibytecodec/c_codecs.py
@@ -1,7 +1,6 @@
 import py
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
-from rpython.conftest import cdir
 
 UNICODE_REPLACEMENT_CHARACTER = u'\uFFFD'
 
@@ -15,7 +14,7 @@
         return 'EncodeDecodeError(%r, %r, %r)' % (self.start, self.end,
                                                   self.reason)
 
-srcdir = py.path.local(cdir)
+srcdir = py.path.local(__file__).dirpath()
 
 codecs = [
     # _codecs_cn
diff --git a/rpython/translator/c/src/cjkcodecs/README b/pypy/module/_multibytecodec/src/cjkcodecs/README
rename from rpython/translator/c/src/cjkcodecs/README
rename to pypy/module/_multibytecodec/src/cjkcodecs/README
diff --git a/rpython/translator/c/src/cjkcodecs/_codecs_cn.c b/pypy/module/_multibytecodec/src/cjkcodecs/_codecs_cn.c
rename from rpython/translator/c/src/cjkcodecs/_codecs_cn.c
rename to pypy/module/_multibytecodec/src/cjkcodecs/_codecs_cn.c
diff --git a/rpython/translator/c/src/cjkcodecs/_codecs_hk.c b/pypy/module/_multibytecodec/src/cjkcodecs/_codecs_hk.c
rename from rpython/translator/c/src/cjkcodecs/_codecs_hk.c
rename to pypy/module/_multibytecodec/src/cjkcodecs/_codecs_hk.c
diff --git a/rpython/translator/c/src/cjkcodecs/_codecs_iso2022.c b/pypy/module/_multibytecodec/src/cjkcodecs/_codecs_iso2022.c
rename from rpython/translator/c/src/cjkcodecs/_codecs_iso2022.c
rename to pypy/module/_multibytecodec/src/cjkcodecs/_codecs_iso2022.c
diff --git a/rpython/translator/c/src/cjkcodecs/_codecs_jp.c b/pypy/module/_multibytecodec/src/cjkcodecs/_codecs_jp.c
rename from rpython/translator/c/src/cjkcodecs/_codecs_jp.c
rename to pypy/module/_multibytecodec/src/cjkcodecs/_codecs_jp.c
diff --git a/rpython/translator/c/src/cjkcodecs/_codecs_kr.c b/pypy/module/_multibytecodec/src/cjkcodecs/_codecs_kr.c
rename from rpython/translator/c/src/cjkcodecs/_codecs_kr.c
rename to pypy/module/_multibytecodec/src/cjkcodecs/_codecs_kr.c
diff --git a/rpython/translator/c/src/cjkcodecs/_codecs_tw.c b/pypy/module/_multibytecodec/src/cjkcodecs/_codecs_tw.c
rename from rpython/translator/c/src/cjkcodecs/_codecs_tw.c
rename to pypy/module/_multibytecodec/src/cjkcodecs/_codecs_tw.c
diff --git a/rpython/translator/c/src/cjkcodecs/alg_jisx0201.h b/pypy/module/_multibytecodec/src/cjkcodecs/alg_jisx0201.h
rename from rpython/translator/c/src/cjkcodecs/alg_jisx0201.h
rename to pypy/module/_multibytecodec/src/cjkcodecs/alg_jisx0201.h
diff --git a/rpython/translator/c/src/cjkcodecs/cjkcodecs.h b/pypy/module/_multibytecodec/src/cjkcodecs/cjkcodecs.h
rename from rpython/translator/c/src/cjkcodecs/cjkcodecs.h
rename to pypy/module/_multibytecodec/src/cjkcodecs/cjkcodecs.h
diff --git a/rpython/translator/c/src/cjkcodecs/emu_jisx0213_2000.h b/pypy/module/_multibytecodec/src/cjkcodecs/emu_jisx0213_2000.h
rename from rpython/translator/c/src/cjkcodecs/emu_jisx0213_2000.h
rename to pypy/module/_multibytecodec/src/cjkcodecs/emu_jisx0213_2000.h
diff --git a/rpython/translator/c/src/cjkcodecs/mappings_cn.h b/pypy/module/_multibytecodec/src/cjkcodecs/mappings_cn.h
rename from rpython/translator/c/src/cjkcodecs/mappings_cn.h
rename to pypy/module/_multibytecodec/src/cjkcodecs/mappings_cn.h
diff --git a/rpython/translator/c/src/cjkcodecs/mappings_hk.h b/pypy/module/_multibytecodec/src/cjkcodecs/mappings_hk.h
rename from rpython/translator/c/src/cjkcodecs/mappings_hk.h
rename to pypy/module/_multibytecodec/src/cjkcodecs/mappings_hk.h
diff --git a/rpython/translator/c/src/cjkcodecs/mappings_jisx0213_pair.h b/pypy/module/_multibytecodec/src/cjkcodecs/mappings_jisx0213_pair.h
rename from rpython/translator/c/src/cjkcodecs/mappings_jisx0213_pair.h
rename to pypy/module/_multibytecodec/src/cjkcodecs/mappings_jisx0213_pair.h
diff --git a/rpython/translator/c/src/cjkcodecs/mappings_jp.h b/pypy/module/_multibytecodec/src/cjkcodecs/mappings_jp.h
rename from rpython/translator/c/src/cjkcodecs/mappings_jp.h
rename to pypy/module/_multibytecodec/src/cjkcodecs/mappings_jp.h
diff --git a/rpython/translator/c/src/cjkcodecs/mappings_kr.h b/pypy/module/_multibytecodec/src/cjkcodecs/mappings_kr.h
rename from rpython/translator/c/src/cjkcodecs/mappings_kr.h
rename to pypy/module/_multibytecodec/src/cjkcodecs/mappings_kr.h
diff --git a/rpython/translator/c/src/cjkcodecs/mappings_tw.h b/pypy/module/_multibytecodec/src/cjkcodecs/mappings_tw.h
rename from rpython/translator/c/src/cjkcodecs/mappings_tw.h
rename to pypy/module/_multibytecodec/src/cjkcodecs/mappings_tw.h
diff --git a/rpython/translator/c/src/cjkcodecs/multibytecodec.c b/pypy/module/_multibytecodec/src/cjkcodecs/multibytecodec.c
rename from rpython/translator/c/src/cjkcodecs/multibytecodec.c
rename to pypy/module/_multibytecodec/src/cjkcodecs/multibytecodec.c
diff --git a/rpython/translator/c/src/cjkcodecs/multibytecodec.h b/pypy/module/_multibytecodec/src/cjkcodecs/multibytecodec.h
rename from rpython/translator/c/src/cjkcodecs/multibytecodec.h
rename to pypy/module/_multibytecodec/src/cjkcodecs/multibytecodec.h
diff --git a/pypy/module/cppyy/test/conftest.py b/pypy/module/cppyy/test/conftest.py
--- a/pypy/module/cppyy/test/conftest.py
+++ b/pypy/module/cppyy/test/conftest.py
@@ -1,5 +1,6 @@
 import py
 
+ at py.test.mark.tryfirst
 def pytest_runtest_setup(item):
     if py.path.local.sysfind('genreflex') is None:
         py.test.skip("genreflex is not installed")
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -2,13 +2,13 @@
 Implementation of the interpreter-level default import logic.
 """
 
-import sys, os, stat
+import sys, os, stat, genericpath
 
 from pypy.interpreter.module import Module
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.typedef import TypeDef, generic_new_descr
 from pypy.interpreter.error import OperationError, oefmt
-from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.baseobjspace import W_Root, CannotHaveLock
 from pypy.interpreter.eval import Code
 from pypy.interpreter.pycode import PyCode
 from rpython.rlib import streamio, jit
@@ -528,7 +528,8 @@
 
             path = space.str0_w(w_pathitem)
             filepart = os.path.join(path, partname)
-            if os.path.isdir(filepart) and case_ok(filepart):
+            # os.path.isdir on win32 is not rpython when pywin32 installed
+            if genericpath.isdir(filepart) and case_ok(filepart):
                 initfile = os.path.join(filepart, '__init__')
                 modtype, _, _ = find_modtype(space, initfile)
                 if modtype in (PY_SOURCE, PY_COMPILED):
@@ -585,7 +586,8 @@
         return space.call_method(find_info.w_loader, "load_module", w_modulename)
 
     if find_info.modtype == C_BUILTIN:
-        return space.getbuiltinmodule(find_info.filename, force_init=True)
+        return space.getbuiltinmodule(find_info.filename, force_init=True,
+                                      reuse=reuse)
 
     if find_info.modtype in (PY_SOURCE, PY_COMPILED, C_EXTENSION, PKG_DIRECTORY):
         w_mod = None
@@ -759,26 +761,14 @@
         me = self.space.getexecutioncontext()   # used as thread ident
         return self.lockowner is me
 
-    def _can_have_lock(self):
-        # hack: we can't have self.lock != None during translation,
-        # because prebuilt lock objects are not allowed.  In this
-        # special situation we just don't lock at all (translation is
-        # not multithreaded anyway).
-        if we_are_translated():
-            return True     # we need a lock at run-time
-        elif self.space.config.translating:
-            assert self.lock is None
-            return False
-        else:
-            return True     # in py.py
-
     def acquire_lock(self):
         # this function runs with the GIL acquired so there is no race
         # condition in the creation of the lock
         if self.lock is None:
-            if not self._can_have_lock():
+            try:
+                self.lock = self.space.allocate_lock()
+            except CannotHaveLock:
                 return
-            self.lock = self.space.allocate_lock()
         me = self.space.getexecutioncontext()   # used as thread ident
         if self.lockowner is me:
             pass    # already acquired by the current thread
@@ -796,7 +786,7 @@
                 # Too bad.  This situation can occur if a fork() occurred
                 # with the import lock held, and we're the child.
                 return
-            if not self._can_have_lock():
+            if self.lock is None:   # CannotHaveLock occurred
                 return
             space = self.space
             raise OperationError(space.w_RuntimeError,
diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py
--- a/pypy/module/imp/test/test_app.py
+++ b/pypy/module/imp/test/test_app.py
@@ -219,7 +219,6 @@
 
     def test_builtin_reimport(self):
         # from https://bugs.pypy.org/issue1514
-        skip("fix me")
         import sys, marshal
 
         old = marshal.loads
@@ -239,7 +238,6 @@
         # taken from https://bugs.pypy.org/issue1514, with extra cases
         # that show a difference with CPython: we can get on CPython
         # several module objects for the same built-in module :-(
-        skip("several built-in module objects: not supported by pypy")
         import sys, marshal
 
         old = marshal.loads
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -652,7 +652,6 @@
         assert hasattr(time, 'clock')
 
     def test_reimport_builtin_simple_case_2(self):
-        skip("fix me")
         import sys, time
         time.foo = "bar"
         del sys.modules['time']
@@ -661,19 +660,18 @@
 
     def test_reimport_builtin(self):
         import imp, sys, time
-        skip("fix me")
         oldpath = sys.path
-        time.tzset = "<test_reimport_builtin removed this>"
+        time.tzname = "<test_reimport_builtin removed this>"
 
         del sys.modules['time']
         import time as time1
         assert sys.modules['time'] is time1
 
-        assert time.tzset == "<test_reimport_builtin removed this>"
+        assert time.tzname == "<test_reimport_builtin removed this>"
 
-        imp.reload(time1)   # don't leave a broken time.tzset behind
+        imp.reload(time1)   # don't leave a broken time.tzname behind
         import time
-        assert time.tzset != "<test_reimport_builtin removed this>"
+        assert time.tzname != "<test_reimport_builtin removed this>"
 
     def test_reload_infinite(self):
         import infinite_reload
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
@@ -23,6 +23,7 @@
 
         'set_string_function': 'appbridge.set_string_function',
         'typeinfo': 'descriptor.get_dtype_cache(space).w_typeinfo',
+        'nditer': 'nditer.nditer',
     }
     for c in ['MAXDIMS', 'CLIP', 'WRAP', 'RAISE']:
         interpleveldefs[c] = 'space.wrap(constants.%s)' % c
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,3 +1,5 @@
+from __future__ import absolute_import
+
 import math
 
 import _numpypy
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
@@ -37,7 +37,7 @@
                         "unegative", "flat", "tostring","count_nonzero",
                         "argsort"]
 TWO_ARG_FUNCTIONS = ["dot", 'take']
-TWO_ARG_FUNCTIONS_OR_NONE = ['view']
+TWO_ARG_FUNCTIONS_OR_NONE = ['view', 'astype']
 THREE_ARG_FUNCTIONS = ['where']
 
 class W_TypeObject(W_Root):
@@ -388,6 +388,8 @@
             w_res = w_lhs.descr_mul(interp.space, w_rhs)
         elif self.name == '-':
             w_res = w_lhs.descr_sub(interp.space, w_rhs)
+        elif self.name == '**':
+            w_res = w_lhs.descr_pow(interp.space, w_rhs)
         elif self.name == '->':
             if isinstance(w_rhs, FloatObject):
                 w_rhs = IntObject(int(w_rhs.floatval))
@@ -596,6 +598,8 @@
             arg = self.args[1].execute(interp)
             if self.name == 'view':
                 w_res = arr.descr_view(interp.space, arg)
+            elif self.name == 'astype':
+                w_res = arr.descr_astype(interp.space, arg)
             else:
                 assert False
         else:
@@ -620,7 +624,7 @@
     (':', 'colon'),
     ('\w+', 'identifier'),
     ('\]', 'array_right'),
-    ('(->)|[\+\-\*\/]', 'operator'),
+    ('(->)|[\+\-\*\/]+', 'operator'),
     ('=', 'assign'),
     (',', 'comma'),
     ('\|', 'pipe'),
diff --git a/pypy/module/micronumpy/iterators.py b/pypy/module/micronumpy/iterators.py
--- a/pypy/module/micronumpy/iterators.py
+++ b/pypy/module/micronumpy/iterators.py
@@ -42,6 +42,7 @@
 """
 from rpython.rlib import jit
 from pypy.module.micronumpy import support
+from pypy.module.micronumpy.strides import calc_strides
 from pypy.module.micronumpy.base import W_NDimArray
 
 
@@ -90,32 +91,41 @@
         self.shape_m1 = [s - 1 for s in shape]
         self.strides = strides
         self.backstrides = backstrides
-        self.reset()
 
+        self.index = 0
+        self.indices = [0] * len(shape)
+        self.offset = array.start
+
+    @jit.unroll_safe
     def reset(self):
         self.index = 0
-        self.indices = [0] * len(self.shape_m1)
+        for i in xrange(self.ndim_m1, -1, -1):
+            self.indices[i] = 0
         self.offset = self.array.start
 
+    @jit.unroll_safe
     def next(self):
         self.index += 1
         for i in xrange(self.ndim_m1, -1, -1):
-            if self.indices[i] < self.shape_m1[i]:
-                self.indices[i] += 1
+            idx = self.indices[i]
+            if idx < self.shape_m1[i]:
+                self.indices[i] = idx + 1
                 self.offset += self.strides[i]
                 break
             else:
                 self.indices[i] = 0
                 self.offset -= self.backstrides[i]
 
+    @jit.unroll_safe
     def next_skip_x(self, step):
         assert step >= 0
         if step == 0:
             return
         self.index += step
         for i in xrange(self.ndim_m1, -1, -1):
-            if self.indices[i] < (self.shape_m1[i] + 1) - step:
-                self.indices[i] += step
+            idx = self.indices[i]
+            if idx < (self.shape_m1[i] + 1) - step:
+                self.indices[i] = idx + step
                 self.offset += self.strides[i] * step
                 break
             else:
@@ -139,6 +149,39 @@
         self.array.setitem(self.offset, elem)
 
 
+class SliceIterator(ArrayIter):
+    def __init__(self, arr, strides, backstrides, shape, order="C",
+                    backward=False, dtype=None):
+        if dtype is None:
+            dtype = arr.implementation.dtype
+        self.dtype = dtype
+        self.arr = arr
+        if backward:
+            self.slicesize = shape[0]
+            self.gap = [support.product(shape[1:]) * dtype.elsize]
+            strides = strides[1:]
+            backstrides = backstrides[1:]
+            shape = shape[1:]
+            strides.reverse()
+            backstrides.reverse()
+            shape.reverse()
+            size = support.product(shape)
+        else:
+            shape = [support.product(shape)]
+            strides, backstrides = calc_strides(shape, dtype, order)
+            size = 1
+            self.slicesize = support.product(shape)
+            self.gap = strides
+
+        ArrayIter.__init__(self, arr.implementation, size, shape, strides, backstrides)
+
+    def getslice(self):
+        from pypy.module.micronumpy.concrete import SliceArray
+        retVal = SliceArray(self.offset, self.gap, self.backstrides,
+        [self.slicesize], self.arr.implementation, self.arr, self.dtype)
+        return retVal
+
+
 def AxisIter(array, shape, axis, cumulative):
     strides = array.get_strides()
     backstrides = array.get_backstrides()
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -996,7 +996,8 @@
     descr_cumsum = _reduce_ufunc_impl('add', cumulative=True)
     descr_cumprod = _reduce_ufunc_impl('multiply', cumulative=True)
 
-    def _reduce_argmax_argmin_impl(op_name):
+    def _reduce_argmax_argmin_impl(raw_name):
+        op_name = "arg%s" % raw_name
         def impl(self, space, w_axis=None, w_out=None):
             if not space.is_none(w_axis):
                 raise oefmt(space.w_NotImplementedError,
@@ -1007,18 +1008,17 @@
             if self.get_size() == 0:
                 raise oefmt(space.w_ValueError,
                     "Can't call %s on zero-size arrays", op_name)
-            op = getattr(loop, op_name)
             try:
-                res = op(self)
+                getattr(self.get_dtype().itemtype, raw_name)
             except AttributeError:
                 raise oefmt(space.w_NotImplementedError,
                             '%s not implemented for %s',
                             op_name, self.get_dtype().get_name())
-            return space.wrap(res)
-        return func_with_new_name(impl, "reduce_arg%s_impl" % op_name)
+            return space.wrap(getattr(loop, op_name)(self))
+        return func_with_new_name(impl, "reduce_%s_impl" % op_name)
 
-    descr_argmax = _reduce_argmax_argmin_impl("argmax")
-    descr_argmin = _reduce_argmax_argmin_impl("argmin")
+    descr_argmax = _reduce_argmax_argmin_impl("max")
+    descr_argmin = _reduce_argmax_argmin_impl("min")
 
     def descr_int(self, space):
         if self.get_size() != 1:
diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/nditer.py
@@ -0,0 +1,595 @@
+from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.typedef import TypeDef, GetSetProperty
+from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
+from pypy.interpreter.error import OperationError
+from pypy.module.micronumpy.base import W_NDimArray, convert_to_array
+from pypy.module.micronumpy.strides import (calculate_broadcast_strides,
+                                             shape_agreement, shape_agreement_multiple)
+from pypy.module.micronumpy.iterators import ArrayIter, SliceIterator
+from pypy.module.micronumpy.concrete import SliceArray
+from pypy.module.micronumpy.descriptor import decode_w_dtype
+from pypy.module.micronumpy import ufuncs, support
+
+
+class AbstractIterator(object):
+    def done(self):
+        raise NotImplementedError("Abstract Class")
+
+    def next(self):
+        raise NotImplementedError("Abstract Class")
+
+    def getitem(self, space, array):
+        raise NotImplementedError("Abstract Class")
+
+class IteratorMixin(object):
+    _mixin_ = True
+    def __init__(self, it, op_flags):
+        self.it = it
+        self.op_flags = op_flags
+
+    def done(self):
+        return self.it.done()
+
+    def next(self):
+        self.it.next()
+
+    def getitem(self, space, array):
+        return self.op_flags.get_it_item[self.index](space, array, self.it)
+
+    def setitem(self, space, array, val):
+        xxx
+
+class BoxIterator(IteratorMixin, AbstractIterator):
+    index = 0
+
+class ExternalLoopIterator(IteratorMixin, AbstractIterator):
+    index = 1
+
+def parse_op_arg(space, name, w_op_flags, n, parse_one_arg):
+    ret = []
+    if space.is_w(w_op_flags, space.w_None):
+        for i in range(n):
+            ret.append(OpFlag())
+    elif not space.isinstance_w(w_op_flags, space.w_tuple) and not \
+             space.isinstance_w(w_op_flags, space.w_list):
+        raise OperationError(space.w_ValueError, space.wrap(
+                '%s must be a tuple or array of per-op flag-tuples' % name))
+    else:
+        w_lst = space.listview(w_op_flags)
+        if space.isinstance_w(w_lst[0], space.w_tuple) or \
+           space.isinstance_w(w_lst[0], space.w_list):
+            if len(w_lst) != n:
+                raise OperationError(space.w_ValueError, space.wrap(
+                   '%s must be a tuple or array of per-op flag-tuples' % name))
+            for item in w_lst:
+                ret.append(parse_one_arg(space, space.listview(item)))
+        else:
+            op_flag = parse_one_arg(space, w_lst)
+            for i in range(n):
+                ret.append(op_flag)
+    return ret
+
+class OpFlag(object):
+    def __init__(self):
+        self.rw = 'r'
+        self.broadcast = True
+        self.force_contig = False
+        self.force_align = False
+        self.native_byte_order = False
+        self.tmp_copy = ''
+        self.allocate = False
+        self.get_it_item = (get_readonly_item, get_readonly_slice)
+
+def get_readonly_item(space, array, it):
+    return space.wrap(it.getitem())
+
+def get_readwrite_item(space, array, it):
+    #create a single-value view (since scalars are not views)
+    res = SliceArray(it.array.start + it.offset, [0], [0], [1,], it.array, array)
+    #it.dtype.setitem(res, 0, it.getitem())
+    return W_NDimArray(res)
+
+def get_readonly_slice(space, array, it):
+    return W_NDimArray(it.getslice().readonly())
+
+def get_readwrite_slice(space, array, it):
+    return W_NDimArray(it.getslice())
+
+def parse_op_flag(space, lst):
+    op_flag = OpFlag()
+    for w_item in lst:
+        item = space.str_w(w_item)
+        if item == 'readonly':
+            op_flag.rw = 'r'
+        elif item == 'readwrite':
+            op_flag.rw = 'rw'
+        elif item == 'writeonly':
+            op_flag.rw = 'w'
+        elif item == 'no_broadcast':
+            op_flag.broadcast = False
+        elif item == 'contig':
+            op_flag.force_contig = True
+        elif item == 'aligned':
+            op_flag.force_align = True
+        elif item == 'nbo':
+            op_flag.native_byte_order = True
+        elif item == 'copy':
+            op_flag.tmp_copy = 'r'
+        elif item == 'updateifcopy':
+            op_flag.tmp_copy = 'rw'
+        elif item == 'allocate':
+            op_flag.allocate = True
+        elif item == 'no_subtype':
+            raise OperationError(space.w_NotImplementedError, space.wrap(
+                    '"no_subtype" op_flag not implemented yet'))
+        elif item == 'arraymask':
+            raise OperationError(space.w_NotImplementedError, space.wrap(
+                    '"arraymask" op_flag not implemented yet'))
+        elif item == 'writemask':
+            raise OperationError(space.w_NotImplementedError, space.wrap(
+                    '"writemask" op_flag not implemented yet'))
+        else:
+            raise OperationError(space.w_ValueError, space.wrap(
+                    'op_flags must be a tuple or array of per-op flag-tuples'))
+        if op_flag.rw == 'r':
+            op_flag.get_it_item = (get_readonly_item, get_readonly_slice)
+        elif op_flag.rw == 'rw':
+            op_flag.get_it_item = (get_readwrite_item, get_readwrite_slice)
+        elif op_flag.rw == 'w':
+            # XXX Extra logic needed to make sure writeonly
+            op_flag.get_it_item = (get_readwrite_item, get_readwrite_slice)
+    return op_flag
+
+def parse_func_flags(space, nditer, w_flags):
+    if space.is_w(w_flags, space.w_None):
+        return
+    elif not space.isinstance_w(w_flags, space.w_tuple) and not \
+             space.isinstance_w(w_flags, space.w_list):
+        raise OperationError(space.w_ValueError, space.wrap(
+                'Iter global flags must be a list or tuple of strings'))
+    lst = space.listview(w_flags)
+    for w_item in lst:
+        if not space.isinstance_w(w_item, space.w_str) and not \
+               space.isinstance_w(w_item, space.w_unicode):
+            typename = space.type(w_item).getname(space)
+            raise OperationError(space.w_TypeError, space.wrap(
+                    'expected string or Unicode object, %s found' % typename))
+        item = space.str_w(w_item)
+        if item == 'external_loop':
+            raise OperationError(space.w_NotImplementedError, space.wrap(
+                'nditer external_loop not implemented yet'))
+            nditer.external_loop = True
+        elif item == 'buffered':
+            raise OperationError(space.w_NotImplementedError, space.wrap(
+                'nditer buffered not implemented yet'))
+            # For numpy compatability
+            nditer.buffered = True
+        elif item == 'c_index':
+            nditer.tracked_index = 'C'
+        elif item == 'f_index':
+            nditer.tracked_index = 'F'
+        elif item == 'multi_index':
+            nditer.tracked_index = 'multi'
+        elif item == 'common_dtype':
+            nditer.common_dtype = True
+        elif item == 'delay_bufalloc':
+            nditer.delay_bufalloc = True
+        elif item == 'grow_inner':
+            nditer.grow_inner = True
+        elif item == 'ranged':
+            nditer.ranged = True
+        elif item == 'refs_ok':
+            nditer.refs_ok = True
+        elif item == 'reduce_ok':
+            raise OperationError(space.w_NotImplementedError, space.wrap(
+                'nditer reduce_ok not implemented yet'))
+            nditer.reduce_ok = True
+        elif item == 'zerosize_ok':
+            nditer.zerosize_ok = True
+        else:
+            raise OperationError(space.w_ValueError, space.wrap(
+                    'Unexpected iterator global flag "%s"' % item))
+    if nditer.tracked_index and nditer.external_loop:
+            raise OperationError(space.w_ValueError, space.wrap(
+                'Iterator flag EXTERNAL_LOOP cannot be used if an index or '
+                'multi-index is being tracked'))
+
+def is_backward(imp, order):
+    if order == 'K' or (order == 'C' and imp.order == 'C'):
+        return False
+    elif order =='F' and imp.order == 'C':
+        return True
+    else:
+        raise NotImplementedError('not implemented yet')
+
+def get_iter(space, order, arr, shape, dtype):
+    imp = arr.implementation
+    backward = is_backward(imp, order)
+    if arr.is_scalar():
+        return ArrayIter(imp, 1, [], [], [])
+    if (imp.strides[0] < imp.strides[-1] and not backward) or \
+       (imp.strides[0] > imp.strides[-1] and backward):
+        # flip the strides. Is this always true for multidimension?
+        strides = imp.strides[:]
+        backstrides = imp.backstrides[:]
+        shape = imp.shape[:]
+        strides.reverse()
+        backstrides.reverse()
+        shape.reverse()
+    else:
+        strides = imp.strides
+        backstrides = imp.backstrides
+    r = calculate_broadcast_strides(strides, backstrides, imp.shape,
+                                    shape, backward)
+    return ArrayIter(imp, imp.get_size(), shape, r[0], r[1])
+
+def get_external_loop_iter(space, order, arr, shape):
+    imp = arr.implementation
+    backward = is_backward(imp, order)
+    return SliceIterator(arr, imp.strides, imp.backstrides, shape, order=order, backward=backward)
+
+def convert_to_array_or_none(space, w_elem):
+    '''
+    None will be passed through, all others will be converted
+    '''
+    if space.is_none(w_elem):
+        return None
+    return convert_to_array(space, w_elem)
+
+
+class IndexIterator(object):
+    def __init__(self, shape, backward=False):
+        self.shape = shape
+        self.index = [0] * len(shape)
+        self.backward = backward
+
+    def next(self):
+        # TODO It's probably possible to refactor all the "next" method from each iterator
+        for i in range(len(self.shape) - 1, -1, -1):
+            if self.index[i] < self.shape[i] - 1:
+                self.index[i] += 1
+                break
+            else:
+                self.index[i] = 0
+
+    def getvalue(self):
+        if not self.backward:
+            ret = self.index[-1]
+            for i in range(len(self.shape) - 2, -1, -1):
+                ret += self.index[i] * self.shape[i - 1]
+        else:
+            ret = self.index[0]
+            for i in range(1, len(self.shape)):
+                ret += self.index[i] * self.shape[i - 1]
+        return ret
+
+class W_NDIter(W_Root):
+
+    def __init__(self, space, w_seq, w_flags, w_op_flags, w_op_dtypes, w_casting,
+            w_op_axes, w_itershape, w_buffersize, order):
+        self.order = order
+        self.external_loop = False
+        self.buffered = False
+        self.tracked_index = ''
+        self.common_dtype = False
+        self.delay_bufalloc = False
+        self.grow_inner = False
+        self.ranged = False
+        self.refs_ok = False
+        self.reduce_ok = False
+        self.zerosize_ok = False
+        self.index_iter = None
+        self.done = False
+        self.first_next = True
+        self.op_axes = []
+        # convert w_seq operands to a list of W_NDimArray
+        if space.isinstance_w(w_seq, space.w_tuple) or \
+           space.isinstance_w(w_seq, space.w_list):
+            w_seq_as_list = space.listview(w_seq)
+            self.seq = [convert_to_array_or_none(space, w_elem) for w_elem in w_seq_as_list]
+        else:
+            self.seq =[convert_to_array(space, w_seq)]
+
+        parse_func_flags(space, self, w_flags)
+        self.op_flags = parse_op_arg(space, 'op_flags', w_op_flags,
+                                     len(self.seq), parse_op_flag)
+        # handle w_op_axes
+        if not space.is_none(w_op_axes):
+            self.set_op_axes(space, w_op_axes)
+
+        # handle w_op_dtypes part 1: creating self.dtypes list from input
+        if not space.is_none(w_op_dtypes):
+            w_seq_as_list = space.listview(w_op_dtypes)
+            self.dtypes = [decode_w_dtype(space, w_elem) for w_elem in w_seq_as_list]
+            if len(self.dtypes) != len(self.seq):
+                raise OperationError(space.w_ValueError, space.wrap(
+                    "op_dtypes must be a tuple/list matching the number of ops"))
+        else:
+            self.dtypes = []
+
+        # handle None or writable operands, calculate my shape
+        self.iters=[]
+        outargs = [i for i in range(len(self.seq)) \
+                        if self.seq[i] is None or self.op_flags[i].rw == 'w']
+        if len(outargs) > 0:
+            out_shape = shape_agreement_multiple(space, [self.seq[i] for i in outargs])
+        else:
+            out_shape = None
+        self.shape = iter_shape = shape_agreement_multiple(space, self.seq,
+                                                           shape=out_shape)
+        if len(outargs) > 0:
+            # Make None operands writeonly and flagged for allocation
+            if len(self.dtypes) > 0:
+                out_dtype = self.dtypes[outargs[0]]
+            else:
+                out_dtype = None
+                for i in range(len(self.seq)):
+                    if self.seq[i] is None:
+                        self.op_flags[i].get_it_item = (get_readwrite_item,
+                                                    get_readwrite_slice)
+                        self.op_flags[i].allocate = True
+                        continue
+                    if self.op_flags[i].rw == 'w':
+                        continue
+                    out_dtype = ufuncs.find_binop_result_dtype(space,
+                                                self.seq[i].get_dtype(), out_dtype)
+            for i in outargs:
+                if self.seq[i] is None:
+                    # XXX can we postpone allocation to later?
+                    self.seq[i] = W_NDimArray.from_shape(space, iter_shape, out_dtype)
+                else:
+                    if not self.op_flags[i].broadcast:
+                        # Raises if ooutput cannot be broadcast
+                        shape_agreement(space, iter_shape, self.seq[i], False)
+
+        if self.tracked_index != "":
+            if self.order == "K":
+                self.order = self.seq[0].implementation.order
+            if self.tracked_index == "multi":
+                backward = False
+            else:
+                backward = self.order != self.tracked_index
+            self.index_iter = IndexIterator(iter_shape, backward=backward)
+
+        # handle w_op_dtypes part 2: copy where needed if possible
+        if len(self.dtypes) > 0:
+            for i in range(len(self.seq)):
+                selfd = self.dtypes[i]
+                seq_d = self.seq[i].get_dtype()
+                if not selfd:
+                    self.dtypes[i] = seq_d
+                elif selfd != seq_d:
+                    if not 'r' in self.op_flags[i].tmp_copy:
+                        raise OperationError(space.w_TypeError, space.wrap(
+                            "Iterator operand required copying or buffering for operand %d" % i))
+                    impl = self.seq[i].implementation
+                    new_impl = impl.astype(space, selfd)
+                    self.seq[i] = W_NDimArray(new_impl)
+        else:
+            #copy them from seq
+            self.dtypes = [s.get_dtype() for s in self.seq]
+
+        # create an iterator for each operand
+        if self.external_loop:
+            for i in range(len(self.seq)):
+                self.iters.append(ExternalLoopIterator(get_external_loop_iter(space, self.order,
+                                self.seq[i], iter_shape), self.op_flags[i]))
+        else:
+            for i in range(len(self.seq)):
+                self.iters.append(BoxIterator(get_iter(space, self.order,
+                                    self.seq[i], iter_shape, self.dtypes[i]),
+                                 self.op_flags[i]))
+    def set_op_axes(self, space, w_op_axes):
+        if space.len_w(w_op_axes) != len(self.seq):
+            raise OperationError(space.w_ValueError, space.wrap("op_axes must be a tuple/list matching the number of ops"))
+        op_axes = space.listview(w_op_axes)
+        l = -1
+        for w_axis in op_axes:
+            if not space.is_none(w_axis):
+                axis_len = space.len_w(w_axis)
+                if l == -1:
+                    l = axis_len
+                elif axis_len != l:
+                    raise OperationError(space.w_ValueError, space.wrap("Each entry of op_axes must have the same size"))
+                self.op_axes.append([space.int_w(x) if not space.is_none(x) else -1 for x in space.listview(w_axis)])
+        if l == -1:
+            raise OperationError(space.w_ValueError, space.wrap("If op_axes is provided, at least one list of axes must be contained within it"))
+        raise Exception('xxx TODO')
+        # Check that values make sense:
+        # - in bounds for each operand
+        # ValueError: Iterator input op_axes[0][3] (==3) is not a valid axis of op[0], which has 2 dimensions
+        # - no repeat axis
+        # ValueError: The 'op_axes' provided to the iterator constructor for operand 1 contained duplicate value 0
+
+    def descr_iter(self, space):
+        return space.wrap(self)
+
+    def descr_getitem(self, space, w_idx):
+        idx = space.int_w(w_idx)
+        try:
+            ret = space.wrap(self.iters[idx].getitem(space, self.seq[idx]))
+        except IndexError:
+            raise OperationError(space.w_IndexError, space.wrap("Iterator operand index %d is out of bounds" % idx))
+        return ret
+
+    def descr_setitem(self, space, w_idx, w_value):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_len(self, space):
+        space.wrap(len(self.iters))
+
+    def descr_next(self, space):
+        for it in self.iters:
+            if not it.done():
+                break
+        else:
+            self.done = True
+            raise OperationError(space.w_StopIteration, space.w_None)
+        res = []
+        if self.index_iter:
+            if not self.first_next:
+                self.index_iter.next()
+            else:
+                self.first_next = False
+        for i in range(len(self.iters)):
+            res.append(self.iters[i].getitem(space, self.seq[i]))
+            self.iters[i].next()
+        if len(res) <2:
+            return res[0]
+        return space.newtuple(res)
+
+    def iternext(self):
+        if self.index_iter:
+            self.index_iter.next()
+        for i in range(len(self.iters)):
+            self.iters[i].next()
+        for it in self.iters:
+            if not it.done():
+                break
+        else:
+            self.done = True
+            return self.done
+        return self.done
+
+    def descr_iternext(self, space):
+        return space.wrap(self.iternext())
+
+    def descr_copy(self, space):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_debug_print(self, space):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_enable_external_loop(self, space):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    @unwrap_spec(axis=int)
+    def descr_remove_axis(self, space, axis):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_remove_multi_index(self, space, w_multi_index):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_reset(self, space):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_get_operands(self, space):
+        l_w = []
+        for op in self.seq:
+            l_w.append(op.descr_view(space))
+        return space.newlist(l_w)
+
+    def descr_get_dtypes(self, space):
+        res = [None] * len(self.seq)
+        for i in range(len(self.seq)):
+            res[i] = self.seq[i].descr_get_dtype(space)
+        return space.newtuple(res)
+
+    def descr_get_finished(self, space):
+        return space.wrap(self.done)
+
+    def descr_get_has_delayed_bufalloc(self, space):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_get_has_index(self, space):
+        return space.wrap(self.tracked_index in ["C", "F"])
+
+    def descr_get_index(self, space):
+        if not self.tracked_index in ["C", "F"]:
+            raise OperationError(space.w_ValueError, space.wrap("Iterator does not have an index"))
+        if self.done:
+            raise OperationError(space.w_ValueError, space.wrap("Iterator is past the end"))
+        return space.wrap(self.index_iter.getvalue())
+
+    def descr_get_has_multi_index(self, space):
+        return space.wrap(self.tracked_index == "multi")
+
+    def descr_get_multi_index(self, space):
+        if not self.tracked_index == "multi":
+            raise OperationError(space.w_ValueError, space.wrap("Iterator is not tracking a multi-index"))
+        if self.done:
+            raise OperationError(space.w_ValueError, space.wrap("Iterator is past the end"))
+        return space.newtuple([space.wrap(x) for x in self.index_iter.index])
+
+    def descr_get_iterationneedsapi(self, space):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_get_iterindex(self, space):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_get_itersize(self, space):
+        return space.wrap(support.product(self.shape))
+
+    def descr_get_itviews(self, space):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_get_ndim(self, space):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_get_nop(self, space):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_get_shape(self, space):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+    def descr_get_value(self, space):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            'not implemented yet'))
+
+
+ at unwrap_spec(w_flags = WrappedDefault(None), w_op_flags=WrappedDefault(None),
+             w_op_dtypes = WrappedDefault(None), order=str,
+             w_casting=WrappedDefault(None), w_op_axes=WrappedDefault(None),
+             w_itershape=WrappedDefault(None), w_buffersize=WrappedDefault(None))
+def nditer(space, w_seq, w_flags, w_op_flags, w_op_dtypes, w_casting, w_op_axes,
+             w_itershape, w_buffersize, order='K'):
+    return W_NDIter(space, w_seq, w_flags, w_op_flags, w_op_dtypes, w_casting, w_op_axes,
+            w_itershape, w_buffersize, order)
+
+W_NDIter.typedef = TypeDef(
+    'nditer',
+    __iter__ = interp2app(W_NDIter.descr_iter),
+    __getitem__ = interp2app(W_NDIter.descr_getitem),
+    __setitem__ = interp2app(W_NDIter.descr_setitem),
+    __len__ = interp2app(W_NDIter.descr_len),
+
+    next = interp2app(W_NDIter.descr_next),
+    iternext = interp2app(W_NDIter.descr_iternext),
+    copy = interp2app(W_NDIter.descr_copy),
+    debug_print = interp2app(W_NDIter.descr_debug_print),
+    enable_external_loop = interp2app(W_NDIter.descr_enable_external_loop),
+    remove_axis = interp2app(W_NDIter.descr_remove_axis),
+    remove_multi_index = interp2app(W_NDIter.descr_remove_multi_index),
+    reset = interp2app(W_NDIter.descr_reset),
+
+    operands = GetSetProperty(W_NDIter.descr_get_operands),
+    dtypes = GetSetProperty(W_NDIter.descr_get_dtypes),
+    finished = GetSetProperty(W_NDIter.descr_get_finished),
+    has_delayed_bufalloc = GetSetProperty(W_NDIter.descr_get_has_delayed_bufalloc),
+    has_index = GetSetProperty(W_NDIter.descr_get_has_index),
+    index = GetSetProperty(W_NDIter.descr_get_index),
+    has_multi_index = GetSetProperty(W_NDIter.descr_get_has_multi_index),
+    multi_index = GetSetProperty(W_NDIter.descr_get_multi_index),
+    iterationneedsapi = GetSetProperty(W_NDIter.descr_get_iterationneedsapi),
+    iterindex = GetSetProperty(W_NDIter.descr_get_iterindex),
+    itersize = GetSetProperty(W_NDIter.descr_get_itersize),
+    itviews = GetSetProperty(W_NDIter.descr_get_itviews),
+    ndim = GetSetProperty(W_NDIter.descr_get_ndim),
+    nop = GetSetProperty(W_NDIter.descr_get_nop),
+    shape = GetSetProperty(W_NDIter.descr_get_shape),
+    value = GetSetProperty(W_NDIter.descr_get_value),
+)
diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py
--- a/pypy/module/micronumpy/strides.py
+++ b/pypy/module/micronumpy/strides.py
@@ -282,14 +282,16 @@
 
 
 @jit.unroll_safe
-def shape_agreement_multiple(space, array_list):
+def shape_agreement_multiple(space, array_list, shape=None):
     """ call shape_agreement recursively, allow elements from array_list to
     be None (like w_out)
     """
-    shape = array_list[0].get_shape()
-    for arr in array_list[1:]:
+    for arr in array_list:
         if not space.is_none(arr):
-            shape = shape_agreement(space, shape, arr)
+            if shape is None:
+                shape = arr.get_shape()
+            else:
+                shape = shape_agreement(space, shape, arr)
     return shape
 
 
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
@@ -319,3 +319,14 @@
         ''')
         results = interp.results[0]
         assert isinstance(results, W_NDimArray)
+
+    def test_astype_dtype(self):
+        interp = self.run('''
+        a = [1, 0, 3, 0]
+        b = int
+        c = astype(a, b)
+        c
+        ''')
+        results = interp.results[0]
+        assert isinstance(results, W_NDimArray)
+        assert results.get_dtype().is_int()
diff --git a/pypy/module/micronumpy/test/test_nditer.py b/pypy/module/micronumpy/test/test_nditer.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_nditer.py
@@ -0,0 +1,302 @@
+import py
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+
+class AppTestNDIter(BaseNumpyAppTest):
+    def test_basic(self):
+        from numpy import arange, nditer
+        a = arange(6).reshape(2,3)
+        r = []
+        for x in nditer(a):
+            r.append(x)
+        assert r == [0, 1, 2, 3, 4, 5]
+        r = []
+
+        for x in nditer(a.T):
+            r.append(x)
+        assert r == [0, 1, 2, 3, 4, 5]
+
+    def test_order(self):
+        from numpy import arange, nditer
+        a = arange(6).reshape(2,3)
+        r = []
+        for x in nditer(a, order='C'):
+            r.append(x)
+        assert r == [0, 1, 2, 3, 4, 5]
+        r = []
+        for x in nditer(a, order='F'):
+            r.append(x)
+        assert r == [0, 3, 1, 4, 2, 5]
+
+    def test_readwrite(self):
+        from numpy import arange, nditer
+        a = arange(6).reshape(2,3)
+        for x in nditer(a, op_flags=['readwrite']):
+            x[...] = 2 * x
+        assert (a == [[0, 2, 4], [6, 8, 10]]).all()
+
+    def test_external_loop(self):
+        from numpy import arange, nditer, array
+        a = arange(24).reshape(2, 3, 4)
+        import sys
+        if '__pypy__' in sys.builtin_module_names:
+            raises(NotImplementedError, nditer, a, flags=['external_loop'])
+            skip('nditer external_loop not implmented')
+        r = []
+        n = 0
+        for x in nditer(a, flags=['external_loop']):
+            r.append(x)
+            n += 1
+        assert n == 1
+        assert (array(r) == range(24)).all()
+        r = []
+        n = 0
+        for x in nditer(a, flags=['external_loop'], order='F'):
+            r.append(x)
+            n += 1
+        assert n == 12
+        assert (array(r) == [[ 0, 12], [ 4, 16], [ 8, 20], [ 1, 13], [ 5, 17], [ 9, 21], [ 2, 14], [ 6, 18], [10, 22], [ 3, 15], [ 7, 19], [11, 23]]).all()
+        e = raises(ValueError, 'r[0][0] = 0')
+        assert str(e.value) == 'assignment destination is read-only'
+        r = []
+        for x in nditer(a.T, flags=['external_loop'], order='F'):
+            r.append(x)
+        array_r = array(r)
+        assert len(array_r.shape) == 2
+        assert array_r.shape == (1,24)
+        assert (array(r) == arange(24)).all()
+
+    def test_index(self):
+        from numpy import arange, nditer
+        a = arange(6).reshape(2,3)
+
+        r = []
+        it = nditer(a, flags=['c_index'])
+        assert it.has_index
+        for value in it:
+            r.append((value, it.index))
+        assert r == [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]
+        exc = None
+        try:
+            it.index
+        except ValueError, e:
+            exc = e
+        assert exc
+
+        r = []
+        it = nditer(a, flags=['f_index'])
+        assert it.has_index
+        for value in it:
+            r.append((value, it.index))
+        assert r == [(0, 0), (1, 2), (2, 4), (3, 1), (4, 3), (5, 5)]
+
+    @py.test.mark.xfail(reason="Fortran order not implemented")
+    def test_iters_with_different_order(self):
+        from numpy import nditer, array
+
+        a = array([[1, 2], [3, 4]], order="C")
+        b = array([[1, 2], [3, 4]], order="F")
+
+        it = nditer([a, b])
+
+        assert list(it) == zip(range(1, 5), range(1, 5))
+
+    def test_interface(self):
+        from numpy import arange, nditer, zeros
+        import sys
+        a = arange(6).reshape(2,3)
+        r = []
+        it = nditer(a, flags=['f_index'])
+        while not it.finished:
+            r.append((it[0], it.index))
+            it.iternext()
+        assert r == [(0, 0), (1, 2), (2, 4), (3, 1), (4, 3), (5, 5)]
+        it = nditer(a, flags=['multi_index'], op_flags=['writeonly'])
+        if '__pypy__' in sys.builtin_module_names:
+            raises(NotImplementedError, 'it[0] = 3')
+            skip('nditer.__setitem__ not implmented')
+        while not it.finished:
+            it[0] = it.multi_index[1] - it.multi_index[0]
+            it.iternext()
+        assert (a == [[0, 1, 2], [-1, 0, 1]]).all()
+        # b = zeros((2, 3))
+        # exc = raises(ValueError, nditer, b, flags=['c_index', 'external_loop'])
+        # assert str(exc.value).startswith("Iterator flag EXTERNAL_LOOP cannot")
+
+    def test_buffered(self):
+        from numpy import arange, nditer, array
+        a = arange(6).reshape(2,3)
+        import sys
+        if '__pypy__' in sys.builtin_module_names:
+            raises(NotImplementedError, nditer, a, flags=['buffered'])
+            skip('nditer buffered not implmented')
+        r = []
+        for x in nditer(a, flags=['external_loop', 'buffered'], order='F'):
+            r.append(x)
+        array_r = array(r)
+        assert len(array_r.shape) == 2
+        assert array_r.shape == (1, 6)
+        assert (array_r == [0, 3, 1, 4, 2, 5]).all()
+
+    def test_op_dtype(self):
+        from numpy import arange, nditer, sqrt, array
+        a = arange(6).reshape(2,3) - 3
+        exc = raises(TypeError, nditer, a, op_dtypes=['complex'])
+        assert str(exc.value).startswith("Iterator operand required copying or buffering")
+        r = []
+        for x in nditer(a, op_flags=['readonly','copy'],
+                        op_dtypes=['complex128']):
+            r.append(sqrt(x))
+        assert abs((array(r) - [1.73205080757j, 1.41421356237j, 1j, 0j,
+                1+0j, 1.41421356237+0j]).sum()) < 1e-5
+        r = []
+        for x in nditer(a, op_flags=['copy'],
+                        op_dtypes=['complex128']):
+            r.append(sqrt(x))
+        assert abs((array(r) - [1.73205080757j, 1.41421356237j, 1j, 0j,
+                            1+0j, 1.41421356237+0j]).sum()) < 1e-5
+        multi = nditer([None, array([2, 3], dtype='int64'), array(2., dtype='double')],
+                       op_dtypes = ['int64', 'int64', 'float64'],
+                       op_flags = [['writeonly', 'allocate'], ['readonly'], ['readonly']])
+        for a, b, c in multi:
+            a[...] = b * c
+        assert (multi.operands[0] == [4, 6]).all()
+
+    def test_casting(self):
+        from numpy import arange, nditer
+        import sys
+        a = arange(6.)
+        if '__pypy__' in sys.builtin_module_names:
+            raises(NotImplementedError, nditer, a, flags=['buffered'], op_dtypes=['float32'])
+            skip('nditer casting not implemented yet')
+        exc = raises(TypeError, nditer, a, flags=['buffered'], op_dtypes=['float32'])
+        assert str(exc.value).startswith("Iterator operand 0 dtype could not be cast")
+        r = []
+        for x in nditer(a, flags=['buffered'], op_dtypes=['float32'],
+                                casting='same_kind'):
+            r.append(x)
+        assert r == [0., 1., 2., 3., 4., 5.]
+        exc = raises(TypeError, nditer, a, flags=['buffered'],
+                        op_dtypes=['int32'], casting='same_kind')
+        assert str(exc.value).startswith("Iterator operand 0 dtype could not be cast")
+        r = []
+        b = arange(6)
+        exc = raises(TypeError, nditer, b, flags=['buffered'], op_dtypes=['float64'],
+                                op_flags=['readwrite'], casting='same_kind')
+        assert str(exc.value).startswith("Iterator requested dtype could not be cast")
+
+    def test_broadcast(self):
+        from numpy import arange, nditer
+        a = arange(3)
+        b = arange(6).reshape(2,3)
+        r = []
+        it = nditer([a, b])
+        assert it.itersize == 6
+        for x,y in it:
+            r.append((x, y))
+        assert r == [(0, 0), (1, 1), (2, 2), (0, 3), (1, 4), (2, 5)]
+        a = arange(2)
+        exc = raises(ValueError, nditer, [a, b])
+        assert str(exc.value).find('shapes (2) (2,3)') > 0
+
+    def test_outarg(self):
+        from numpy import nditer, zeros, arange
+        import sys
+        if '__pypy__' in sys.builtin_module_names:
+            raises(NotImplementedError, nditer, [1, 2], flags=['external_loop'])
+            skip('nditer external_loop not implmented')
+
+        def square1(a):
+            it = nditer([a, None])
+            for x,y in it:
+                y[...] = x*x
+            return it.operands[1]
+        assert (square1([1, 2, 3]) == [1, 4, 9]).all()
+
+        def square2(a, out=None):
+            it = nditer([a, out], flags=['external_loop', 'buffered'],
+                        op_flags=[['readonly'],
+                                  ['writeonly', 'allocate', 'no_broadcast']])
+            for x,y in it:
+                y[...] = x*x
+            return it.operands[1]
+        assert (square2([1, 2, 3]) == [1, 4, 9]).all()
+        b = zeros((3, ))
+        c = square2([1, 2, 3], out=b)
+        assert (c == [1., 4., 9.]).all()
+        assert (b == c).all()
+        exc = raises(ValueError, square2, arange(6).reshape(2, 3), out=b)
+        assert str(exc.value).find('cannot be broadcasted') > 0
+
+    def test_outer_product(self):
+        from numpy import nditer, arange
+        a = arange(3)
+        import sys
+        if '__pypy__' in sys.builtin_module_names:
+            raises(NotImplementedError, nditer, a, flags=['external_loop'])
+            skip('nditer external_loop not implmented')
+        b = arange(8).reshape(2,4)
+        it = nditer([a, b, None], flags=['external_loop'],
+                    op_axes=[[0, -1, -1], [-1, 0, 1], None])
+        for x, y, z in it:
+            z[...] = x*y
+        assert it.operands[2].shape == (3, 2, 4)
+        for i in range(a.size):
+            assert (it.operands[2][i] == a[i]*b).all()
+
+    def test_reduction(self):
+        from numpy import nditer, arange, array
+        import sys
+        a = arange(24).reshape(2, 3, 4)
+        b = array(0)
+        if '__pypy__' in sys.builtin_module_names:
+            raises(NotImplementedError, nditer, [a, b], flags=['reduce_ok'])
+            skip('nditer reduce_ok not implemented yet')
+        #reduction operands must be readwrite
+        for x, y in nditer([a, b], flags=['reduce_ok', 'external_loop'],
+                            op_flags=[['readonly'], ['readwrite']]):
+            y[...] += x
+        assert b == 276
+        assert b == a.sum()
+
+        # reduction and allocation requires op_axes and initialization
+        it = nditer([a, None], flags=['reduce_ok', 'external_loop'],
+                    op_flags=[['readonly'], ['readwrite', 'allocate']],
+                    op_axes=[None, [0,1,-1]])
+        it.operands[1][...] = 0
+        for x, y in it:
+            y[...] += x
+
+        assert (it.operands[1] == [[6, 22, 38], [54, 70, 86]]).all()
+        assert (it.operands[1] == a.sum(axis=2)).all()
+
+        # previous example with buffering, requires more flags and reset
+        it = nditer([a, None], flags=['reduce_ok', 'external_loop',
+                                      'buffered', 'delay_bufalloc'],
+                    op_flags=[['readonly'], ['readwrite', 'allocate']],
+                    op_axes=[None, [0,1,-1]])
+        it.operands[1][...] = 0
+        it.reset()
+        for x, y in it:
+            y[...] += x
+
+        assert (it.operands[1] == [[6, 22, 38], [54, 70, 86]]).all()
+        assert (it.operands[1] == a.sum(axis=2)).all()
+
+    def test_get_dtypes(self):
+        from numpy import array, nditer
+        x = array([1, 2])
+        y = array([1.0, 2.0])
+        assert nditer([x, y]).dtypes == (x.dtype, y.dtype)
+
+    def test_multi_index(self):
+        import numpy as np
+        a = np.arange(6).reshape(2, 3)
+        it = np.nditer(a, flags=['multi_index'])
+        res = []
+        while not it.finished:
+            res.append((it[0], it.multi_index))
+            it.iternext()
+        assert res == [(0, (0, 0)), (1, (0, 1)),
+                       (2, (0, 2)), (3, (1, 0)),
+                       (4, (1, 1)), (5, (1, 2))]
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
@@ -94,14 +94,58 @@
         a -> 3
         """
 
-    def test_floatadd(self):
+    def test_float_add(self):
         result = self.run("float_add")
         assert result == 3 + 3
-        py.test.skip("don't run for now")
-        self.check_simple_loop({"raw_load": 1, "float_add": 1,
-                                "raw_store": 1, "int_add": 1,
-                                "int_ge": 1, "guard_false": 1, "jump": 1,
-                                'arraylen_gc': 1})
+        self.check_trace_count(1)
+        self.check_simple_loop({
+            'float_add': 1,
+            'getarrayitem_gc': 3,
+            'getfield_gc': 7,
+            'guard_false': 1,
+            'guard_not_invalidated': 1,
+            'guard_true': 3,
+            'int_add': 9,
+            'int_ge': 1,
+            'int_lt': 3,
+            'jump': 1,
+            'raw_load': 2,
+            'raw_store': 1,
+            'setarrayitem_gc': 3,
+            'setfield_gc': 6,
+        })
+
+    def define_pow():
+        return """
+        a = |30| ** 2
+        a -> 3
+        """
+
+    def test_pow(self):
+        result = self.run("pow")
+        assert result == 3 ** 2
+        self.check_trace_count(1)
+        self.check_simple_loop({
+            'call': 3,
+            'float_add': 1,
+            'float_eq': 3,
+            'float_mul': 2,
+            'float_ne': 1,
+            'getarrayitem_gc': 3,
+            'getfield_gc': 7,
+            'guard_false': 4,
+            'guard_not_invalidated': 1,
+            'guard_true': 5,
+            'int_add': 9,
+            'int_ge': 1,
+            'int_is_true': 1,
+            'int_lt': 3,
+            'jump': 1,
+            'raw_load': 2,
+            'raw_store': 1,
+            'setarrayitem_gc': 3,
+            'setfield_gc': 6,
+        })
 
     def define_sum():
         return """
@@ -482,16 +526,19 @@
         assert result == 1.0
         self.check_trace_count(1)
         self.check_simple_loop({
-            'call': 2,
-            'getfield_gc': 2,
-            'guard_no_exception': 2,
+            'getarrayitem_gc': 2,
+            'getfield_gc': 4,
             'guard_not_invalidated': 1,
-            'guard_true': 1,
+            'guard_true': 3,
+            'int_add': 6,
             'int_gt': 1,
+            'int_lt': 2,
             'int_sub': 1,
             'jump': 1,
             'raw_load': 1,
             'raw_store': 1,
+            'setarrayitem_gc': 2,
+            'setfield_gc': 4,
         })
 
     def define_dot():
@@ -506,36 +553,41 @@
         result = self.run("dot")
         assert result == 184
         self.check_trace_count(3)
-        self.check_simple_loop({'float_add': 1,
-                                'float_mul': 1,
-                                'guard_not_invalidated': 1,
-                                'guard_true': 1,
-                                'int_add': 3,
-                                'int_lt': 1,
-                                'jump': 1,
-                                'raw_load': 2})
-        self.check_resops({'arraylen_gc': 1,
-                           'call': 3,
-                           'float_add': 2,
-                           'float_mul': 2,
-                           'getfield_gc': 26,
-                           'getfield_gc_pure': 24,
-                           'guard_class': 4,
-                           'guard_false': 2,
-                           'guard_no_exception': 3,
-                           'guard_nonnull': 12,
-                           'guard_nonnull_class': 4,
-                           'guard_not_invalidated': 2,
-                           'guard_true': 9,
-                           'guard_value': 4,
-                           'int_add': 6,
-                           'int_ge': 3,
-                           'int_lt': 4,
-                           'jump': 3,
-                           'new_array': 1,
-                           'raw_load': 6,
-                           'raw_store': 1,
-                           'setfield_gc': 3})
+        self.check_simple_loop({
+            'float_add': 1,
+            'float_mul': 1,
+            'guard_not_invalidated': 1,
+            'guard_true': 1,
+            'int_add': 3,
+            'int_lt': 1,
+            'jump': 1,
+            'raw_load': 2,
+        })
+        self.check_resops({
+            'float_add': 2,
+            'float_mul': 2,
+            'getarrayitem_gc': 7,
+            'getarrayitem_gc_pure': 15,
+            'getfield_gc': 35,
+            'getfield_gc_pure': 39,
+            'guard_class': 4,
+            'guard_false': 14,
+            'guard_nonnull': 12,
+            'guard_nonnull_class': 4,
+            'guard_not_invalidated': 2,
+            'guard_true': 13,
+            'guard_value': 4,
+            'int_add': 25,
+            'int_ge': 4,
+            'int_le': 8,
+            'int_lt': 11,
+            'int_sub': 4,
+            'jump': 3,
+            'raw_load': 6,
+            'raw_store': 1,
+            'setarrayitem_gc': 10,
+            'setfield_gc': 14,
+        })
 
     def define_argsort():
         return """
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -442,6 +442,7 @@
         return v1 % v2
 
     @simple_binary_op
+    @jit.look_inside_iff(lambda self, v1, v2: jit.isconstant(v2))
     def pow(self, v1, v2):
         if v2 < 0:
             return 0
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
@@ -3,15 +3,18 @@
 indirection is introduced to make the version tag change less often.
 """
 
+from rpython.rlib import jit, rerased
+
 from pypy.interpreter.baseobjspace import W_Root
-from pypy.objspace.std.dictmultiobject import create_iterator_classes
-from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string
-from pypy.objspace.std.dictmultiobject import ObjectDictStrategy
-from rpython.rlib import jit, rerased
+from pypy.objspace.std.dictmultiobject import (
+    DictStrategy, ObjectDictStrategy, _never_equal_to_string,
+    create_iterator_classes)
+
 
 class VersionTag(object):
     pass
 
+
 class ModuleCell(W_Root):
     def __init__(self, w_value=None):
         self.w_value = w_value
@@ -19,11 +22,17 @@
     def __repr__(self):
         return "<ModuleCell: %s>" % (self.w_value, )
 
+
 def unwrap_cell(w_value):
     if isinstance(w_value, ModuleCell):
         return w_value.w_value
     return w_value
 
+
+def _wrapkey(space, key):
+    return space.wrap(key)
+
+
 class ModuleDictStrategy(DictStrategy):
 
     erase, unerase = rerased.new_erasing_pair("modulecell")
@@ -55,7 +64,7 @@
     def setitem(self, w_dict, w_key, w_value):
         space = self.space
         if space.is_w(space.type(w_key), space.w_str):
-            self.setitem_str(w_dict, self.space.str_w(w_key), w_value)
+            self.setitem_str(w_dict, space.str_w(w_key), w_value)
         else:
             self.switch_to_object_strategy(w_dict)
             w_dict.setitem(w_key, w_value)
@@ -66,8 +75,8 @@
             cell.w_value = w_value
             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 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)
@@ -121,8 +130,8 @@
             return w_dict.getitem(w_key)
 
     def getitem_str(self, w_dict, key):
-        w_res = self.getdictvalue_no_unwrapping(w_dict, key)
-        return unwrap_cell(w_res)
+        cell = self.getdictvalue_no_unwrapping(w_dict, key)
+        return unwrap_cell(cell)
 
     def w_keys(self, w_dict):
         space = self.space
@@ -136,37 +145,43 @@
     def items(self, w_dict):
         space = self.space
         iterator = self.unerase(w_dict.dstorage).iteritems
-        return [space.newtuple([space.wrap(key), unwrap_cell(cell)])
-                    for key, cell in iterator()]
+        return [space.newtuple([_wrapkey(space, key), unwrap_cell(cell)])
+                for key, cell in iterator()]
 
     def clear(self, w_dict):
         self.unerase(w_dict.dstorage).clear()
         self.mutated()
 
     def popitem(self, w_dict):
+        space = self.space
         d = self.unerase(w_dict.dstorage)
-        key, w_value = d.popitem()
+        key, cell = d.popitem()
         self.mutated()
-        return self.space.wrap(key), unwrap_cell(w_value)
+        return _wrapkey(space, key), unwrap_cell(cell)
 
     def switch_to_object_strategy(self, w_dict):
+        space = self.space
         d = self.unerase(w_dict.dstorage)
-        strategy = self.space.fromcache(ObjectDictStrategy)
+        strategy = space.fromcache(ObjectDictStrategy)
         d_new = strategy.unerase(strategy.get_empty_storage())
         for key, cell in d.iteritems():
-            d_new[self.space.wrap(key)] = unwrap_cell(cell)
+            d_new[_wrapkey(space, key)] = unwrap_cell(cell)
         w_dict.strategy = strategy
         w_dict.dstorage = strategy.erase(d_new)
 
     def getiterkeys(self, w_dict):
         return self.unerase(w_dict.dstorage).iterkeys()
+
     def getitervalues(self, w_dict):
         return self.unerase(w_dict.dstorage).itervalues()
+
     def getiteritems(self, w_dict):
         return self.unerase(w_dict.dstorage).iteritems()
-    def wrapkey(space, key):
-        return space.wrap(key)
+
+    wrapkey = _wrapkey
+
     def wrapvalue(space, value):
         return unwrap_cell(value)
 
+
 create_iterator_classes(ModuleDictStrategy)
diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py
--- a/pypy/objspace/std/kwargsdict.py
+++ b/pypy/objspace/std/kwargsdict.py
@@ -1,12 +1,19 @@
-## ----------------------------------------------------------------------------
-## dict strategy (see dictmultiobject.py)
+"""dict implementation specialized for keyword argument dicts.
 
-from rpython.rlib import rerased, jit
+Based on two lists containing unwrapped key value pairs.
+"""
+
+from rpython.rlib import jit, rerased
+
 from pypy.objspace.std.dictmultiobject import (
     DictStrategy, EmptyDictStrategy, ObjectDictStrategy, UnicodeDictStrategy,
     create_iterator_classes)
 
 
+def _wrapkey(space, key):
+    return space.wrap(key)
+
+
 class EmptyKwargsDictStrategy(EmptyDictStrategy):
     def switch_to_unicode_strategy(self, w_dict):
         strategy = self.space.fromcache(KwargsDictStrategy)
@@ -21,7 +28,7 @@
     unerase = staticmethod(unerase)
 
     def wrap(self, key):
-        return self.space.wrap(key)
+        return _wrapkey(self.space, key)
 
     def unwrap(self, wrapped):
         return self.space.str_w(wrapped)
@@ -118,16 +125,14 @@
     def items(self, w_dict):
         space = self.space
         keys, values_w = self.unerase(w_dict.dstorage)
-        result = []
-        for i in range(len(keys)):
-            result.append(space.newtuple([self.wrap(keys[i]), values_w[i]]))
-        return result
+        return [space.newtuple([self.wrap(keys[i]), values_w[i]])
+                for i in range(len(keys))]
 
     def popitem(self, w_dict):
         keys, values_w = self.unerase(w_dict.dstorage)
         key = keys.pop()
         w_value = values_w.pop()
-        return (self.wrap(key), w_value)
+        return self.wrap(key), w_value
 
     def clear(self, w_dict):
         w_dict.dstorage = self.get_empty_storage()
@@ -165,17 +170,15 @@
         keys = self.unerase(w_dict.dstorage)[0]
         return iter(range(len(keys)))
 
-    def wrapkey(space, key):
-        return space.wrap(key)
+    wrapkey = _wrapkey
 
 
 def next_item(self):
     strategy = self.strategy
     assert isinstance(strategy, KwargsDictStrategy)
     for i in self.iterator:
-        keys, values_w = strategy.unerase(
-            self.dictimplementation.dstorage)
-        return self.space.wrap(keys[i]), values_w[i]
+        keys, values_w = strategy.unerase(self.dictimplementation.dstorage)
+        return _wrapkey(self.space, keys[i]), values_w[i]
     else:
         return None, None
 
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
@@ -683,7 +683,7 @@
             raise OperationError(space.w_ValueError,
                                  space.wrap("list modified during sort"))
 
-find_jmp = jit.JitDriver(greens = [], reds = 'auto', name = 'list.find')
+find_jmp = jit.JitDriver(greens = ['tp'], reds = 'auto', name = 'list.find')
 
 class ListStrategy(object):
 
@@ -709,8 +709,9 @@
         space = self.space
         i = start
         # needs to be safe against eq_w mutating stuff
+        tp = space.type(w_item)
         while i < stop and i < w_list.length():
-            find_jmp.jit_merge_point()
+            find_jmp.jit_merge_point(tp=tp)
             if space.eq_w(w_list.getitem(i), w_item):
                 return i
             i += 1
diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py
--- a/pypy/objspace/std/setobject.py
+++ b/pypy/objspace/std/setobject.py
@@ -1070,6 +1070,7 @@
     def _intersect_wrapped(self, w_set, w_other):
         result = newset(self.space)
         for key in self.unerase(w_set.sstorage):
+            self.intersect_jmp.jit_merge_point()
             w_key = self.wrap(key)
             if w_other.has_key(w_key):
                 result[w_key] = None
@@ -1180,6 +1181,9 @@
     erase = staticmethod(erase)
     unerase = staticmethod(unerase)
 
+    intersect_jmp = jit.JitDriver(greens = [], reds = 'auto',
+                                  name='set(bytes).intersect')
+
     def get_empty_storage(self):
         return self.erase({})
 
@@ -1216,6 +1220,9 @@
     erase = staticmethod(erase)
     unerase = staticmethod(unerase)
 
+    intersect_jmp = jit.JitDriver(greens = [], reds = 'auto',
+                                  name='set(unicode).intersect')


More information about the pypy-commit mailing list