[pypy-commit] pypy default: merge heads

arigo noreply at buildbot.pypy.org
Fri Feb 28 10:56:02 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r69542:339fe18d37ef
Date: 2014-02-28 10:55 +0100
http://bitbucket.org/pypy/pypy/changeset/339fe18d37ef/

Log:	merge heads

diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst
--- a/pypy/doc/embedding.rst
+++ b/pypy/doc/embedding.rst
@@ -30,7 +30,8 @@
    it you would not be able to find the standard library (and run pretty much
    nothing). Arguments:
 
-   * ``home``: null terminated path
+   * ``home``: null terminated path to an executable inside the pypy directory
+     (can be a .so name, can be made up)
 
    * ``verbose``: if non-zero, would print error messages to stderr
 
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
@@ -85,3 +85,6 @@
 
 .. branch: remove-intlong-smm
 kills int/long/smalllong/bool multimethods
+
+.. branch: numpy-refactor
+Cleanup micronumpy module
diff --git a/pypy/module/micronumpy/bench/dot.py b/pypy/module/micronumpy/bench/dot.py
--- a/pypy/module/micronumpy/bench/dot.py
+++ b/pypy/module/micronumpy/bench/dot.py
@@ -1,28 +1,32 @@
+import sys
 import time
 
 try:
-    import numpypy
+    import numpypy as numpy
 except ImportError:
-    pass
+    import numpy
 
-import numpy
-
-def get_matrix():
+def get_matrix(n):
     import random
-    n = 502
     x = numpy.zeros((n,n), dtype=numpy.float64)
     for i in range(n):
         for j in range(n):
             x[i][j] = random.random()
     return x
 
-def main():
-    x = get_matrix()
-    y = get_matrix()
+def main(n, r):
+    x = get_matrix(n)
+    y = get_matrix(n)
     a = time.time()
-    #z = numpy.dot(x, y)  # uses numpy possibly-blas-lib dot
-    z = numpy.core.multiarray.dot(x, y)  # uses strictly numpy C dot
+    for _ in xrange(r):
+        #z = numpy.dot(x, y)  # uses numpy possibly-blas-lib dot
+        z = numpy.core.multiarray.dot(x, y)  # uses strictly numpy C dot
     b = time.time()
-    print '%.2f seconds' % (b-a)
+    print '%d runs, %.2f seconds' % (r, b-a)
 
-main()
+n = int(sys.argv[1])
+try:
+    r = int(sys.argv[2])
+except IndexError:
+    r = 1
+main(n, r)
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
@@ -9,7 +9,7 @@
 from rpython.rlib.nonconst import NonConstant
 from pypy.module.micronumpy import boxes, ufuncs
 from pypy.module.micronumpy.arrayops import where
-from pypy.module.micronumpy.base import W_NDimArray
+from pypy.module.micronumpy.ndarray import W_NDimArray
 from pypy.module.micronumpy.ctors import array
 from pypy.module.micronumpy.descriptor import get_dtype_cache
 
diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py
--- a/pypy/module/micronumpy/concrete.py
+++ b/pypy/module/micronumpy/concrete.py
@@ -5,15 +5,18 @@
 from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage, \
     raw_storage_getitem, raw_storage_setitem, RAW_STORAGE
 from rpython.rtyper.lltypesystem import rffi, lltype
-from pypy.module.micronumpy import support, loop, iter
+from pypy.module.micronumpy import support, loop
 from pypy.module.micronumpy.base import convert_to_array, W_NDimArray, \
     ArrayArgumentException
+from pypy.module.micronumpy.iterators import ArrayIter
 from pypy.module.micronumpy.strides import (Chunk, Chunks, NewAxisChunk,
     RecordChunk, calc_strides, calc_new_strides, shape_agreement,
-    calculate_broadcast_strides, calculate_dot_strides)
+    calculate_broadcast_strides)
 
 
 class BaseConcreteArray(object):
+    _immutable_fields_ = ['dtype?', 'storage', 'start', 'size', 'shape[*]',
+                          'strides[*]', 'backstrides[*]', 'order']
     start = 0
     parent = None
 
@@ -283,17 +286,9 @@
                                             self.get_backstrides(),
                                             self.get_shape(), shape,
                                             backward_broadcast)
-            return iter.MultiDimViewIterator(self, self.start,
-                                             r[0], r[1], shape)
-        return iter.ArrayIterator(self)
-
-    def create_axis_iter(self, shape, dim, cum):
-        return iter.AxisIterator(self, shape, dim, cum)
-
-    def create_dot_iter(self, shape, skip):
-        r = calculate_dot_strides(self.get_strides(), self.get_backstrides(),
-                                  shape, skip)
-        return iter.MultiDimViewIterator(self, self.start, r[0], r[1], shape)
+            return ArrayIter(self, support.product(shape), shape, r[0], r[1])
+        return ArrayIter(self, self.get_size(), self.shape,
+                         self.strides, self.backstrides)
 
     def swapaxes(self, space, orig_arr, axis1, axis2):
         shape = self.get_shape()[:]
@@ -357,6 +352,8 @@
                           orig_array)
 
     def set_dtype(self, space, dtype):
+        # size/shape/strides shouldn't change
+        assert dtype.elsize == self.dtype.elsize
         self.dtype = dtype
 
     def argsort(self, space, w_axis):
diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py
deleted file mode 100644
--- a/pypy/module/micronumpy/iter.py
+++ /dev/null
@@ -1,217 +0,0 @@
-""" This is a mini-tutorial on iterators, strides, and
-memory layout. It assumes you are familiar with the terms, see
-http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html
-for a more gentle introduction.
-
-Given an array x: x.shape == [5,6], where each element occupies one byte
-
-At which byte in x.data does the item x[3,4] begin?
-if x.strides==[1,5]:
-    pData = x.pData + (x.start + 3*1 + 4*5)*sizeof(x.pData[0])
-    pData = x.pData + (x.start + 24) * sizeof(x.pData[0])
-so the offset of the element is 24 elements after the first
-
-What is the next element in x after coordinates [3,4]?
-if x.order =='C':
-   next == [3,5] => offset is 28
-if x.order =='F':
-   next == [4,4] => offset is 24
-so for the strides [1,5] x is 'F' contiguous
-likewise, for the strides [6,1] x would be 'C' contiguous.
-
-Iterators have an internal representation of the current coordinates
-(indices), the array, strides, and backstrides. A short digression to
-explain backstrides: what is the coordinate and offset after [3,5] in
-the example above?
-if x.order == 'C':
-   next == [4,0] => offset is 4
-if x.order == 'F':
-   next == [4,5] => offset is 25
-Note that in 'C' order we stepped BACKWARDS 24 while 'overflowing' a
-shape dimension
-  which is back 25 and forward 1,
-  which is x.strides[1] * (x.shape[1] - 1) + x.strides[0]
-so if we precalculate the overflow backstride as
-[x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))]
-we can go faster.
-All the calculations happen in next()
-
-next_skip_x(steps) tries to do the iteration for a number of steps at once,
-but then we cannot guarantee that we only overflow one single shape
-dimension, perhaps we could overflow times in one big step.
-"""
-from rpython.rlib import jit
-from pypy.module.micronumpy import support
-from pypy.module.micronumpy.base import W_NDimArray
-
-
-class PureShapeIterator(object):
-    def __init__(self, shape, idx_w):
-        self.shape = shape
-        self.shapelen = len(shape)
-        self.indexes = [0] * len(shape)
-        self._done = False
-        self.idx_w = [None] * len(idx_w)
-        for i, w_idx in enumerate(idx_w):
-            if isinstance(w_idx, W_NDimArray):
-                self.idx_w[i] = w_idx.create_iter(shape)
-
-    def done(self):
-        return self._done
-
-    @jit.unroll_safe
-    def next(self):
-        for w_idx in self.idx_w:
-            if w_idx is not None:
-                w_idx.next()
-        for i in range(self.shapelen - 1, -1, -1):
-            if self.indexes[i] < self.shape[i] - 1:
-                self.indexes[i] += 1
-                break
-            else:
-                self.indexes[i] = 0
-        else:
-            self._done = True
-
-    @jit.unroll_safe
-    def get_index(self, space, shapelen):
-        return [space.wrap(self.indexes[i]) for i in range(shapelen)]
-
-
-class ArrayIterator(object):
-    def __init__(self, array):
-        self.array = array
-        self.start = array.start
-        self.size = array.get_size()
-        self.ndim_m1 = len(array.shape) - 1
-        self.shape_m1 = [s - 1 for s in array.shape]
-        self.strides = array.strides[:]
-        self.backstrides = array.backstrides[:]
-        self.reset()
-
-    def reset(self):
-        self.index = 0
-        self.indices = [0] * (self.ndim_m1 + 1)
-        self.offset = self.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
-                self.offset += self.strides[i]
-                break
-            else:
-                self.indices[i] = 0
-                self.offset -= self.backstrides[i]
-
-    def next_skip_x(self, step):
-        # XXX implement
-        for _ in range(step):
-            self.next()
-
-    def done(self):
-        return self.index >= self.size
-
-    def getitem(self):
-        return self.array.getitem(self.offset)
-
-    def getitem_bool(self):
-        return self.array.getitem_bool(self.offset)
-
-    def setitem(self, elem):
-        self.array.setitem(self.offset, elem)
-
-
-class MultiDimViewIterator(ArrayIterator):
-    def __init__(self, array, start, strides, backstrides, shape):
-        self.indexes = [0] * len(shape)
-        self.array = array
-        self.shape = shape
-        self.offset = start
-        self.shapelen = len(shape)
-        self._done = self.shapelen == 0 or support.product(shape) == 0
-        self.strides = strides
-        self.backstrides = backstrides
-        self.size = array.size
-
-    @jit.unroll_safe
-    def next(self):
-        offset = self.offset
-        for i in range(self.shapelen - 1, -1, -1):
-            if self.indexes[i] < self.shape[i] - 1:
-                self.indexes[i] += 1
-                offset += self.strides[i]
-                break
-            else:
-                self.indexes[i] = 0
-                offset -= self.backstrides[i]
-        else:
-            self._done = True
-        self.offset = offset
-
-    @jit.unroll_safe
-    def next_skip_x(self, step):
-        for i in range(len(self.shape) - 1, -1, -1):
-            if self.indexes[i] < self.shape[i] - step:
-                self.indexes[i] += step
-                self.offset += self.strides[i] * step
-                break
-            else:
-                remaining_step = (self.indexes[i] + step) // self.shape[i]
-                this_i_step = step - remaining_step * self.shape[i]
-                self.offset += self.strides[i] * this_i_step
-                self.indexes[i] = self.indexes[i] + this_i_step
-                step = remaining_step
-        else:
-            self._done = True
-
-    def done(self):
-        return self._done
-
-    def reset(self):
-        self.offset %= self.size
-
-
-class AxisIterator(ArrayIterator):
-    def __init__(self, array, shape, dim, cumulative):
-        self.shape = shape
-        strides = array.get_strides()
-        backstrides = array.get_backstrides()
-        if cumulative:
-            self.strides = strides
-            self.backstrides = backstrides
-        elif len(shape) == len(strides):
-            # keepdims = True
-            self.strides = strides[:dim] + [0] + strides[dim + 1:]
-            self.backstrides = backstrides[:dim] + [0] + backstrides[dim + 1:]
-        else:
-            self.strides = strides[:dim] + [0] + strides[dim:]
-            self.backstrides = backstrides[:dim] + [0] + backstrides[dim:]
-        self.first_line = True
-        self.indices = [0] * len(shape)
-        self._done = array.get_size() == 0
-        self.offset = array.start
-        self.dim = dim
-        self.array = array
-
-    @jit.unroll_safe
-    def next(self):
-        for i in range(len(self.shape) - 1, -1, -1):
-            if self.indices[i] < self.shape[i] - 1:
-                if i == self.dim:
-                    self.first_line = False
-                self.indices[i] += 1
-                self.offset += self.strides[i]
-                break
-            else:
-                if i == self.dim:
-                    self.first_line = True
-                self.indices[i] = 0
-                self.offset -= self.backstrides[i]
-        else:
-            self._done = True
-
-    def done(self):
-        return self._done
diff --git a/pypy/module/micronumpy/iterators.py b/pypy/module/micronumpy/iterators.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/iterators.py
@@ -0,0 +1,167 @@
+""" This is a mini-tutorial on iterators, strides, and
+memory layout. It assumes you are familiar with the terms, see
+http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html
+for a more gentle introduction.
+
+Given an array x: x.shape == [5,6], where each element occupies one byte
+
+At which byte in x.data does the item x[3,4] begin?
+if x.strides==[1,5]:
+    pData = x.pData + (x.start + 3*1 + 4*5)*sizeof(x.pData[0])
+    pData = x.pData + (x.start + 24) * sizeof(x.pData[0])
+so the offset of the element is 24 elements after the first
+
+What is the next element in x after coordinates [3,4]?
+if x.order =='C':
+   next == [3,5] => offset is 28
+if x.order =='F':
+   next == [4,4] => offset is 24
+so for the strides [1,5] x is 'F' contiguous
+likewise, for the strides [6,1] x would be 'C' contiguous.
+
+Iterators have an internal representation of the current coordinates
+(indices), the array, strides, and backstrides. A short digression to
+explain backstrides: what is the coordinate and offset after [3,5] in
+the example above?
+if x.order == 'C':
+   next == [4,0] => offset is 4
+if x.order == 'F':
+   next == [4,5] => offset is 25
+Note that in 'C' order we stepped BACKWARDS 24 while 'overflowing' a
+shape dimension
+  which is back 25 and forward 1,
+  which is x.strides[1] * (x.shape[1] - 1) + x.strides[0]
+so if we precalculate the overflow backstride as
+[x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))]
+we can go faster.
+All the calculations happen in next()
+
+next_skip_x(steps) tries to do the iteration for a number of steps at once,
+but then we cannot guarantee that we only overflow one single shape
+dimension, perhaps we could overflow times in one big step.
+"""
+from rpython.rlib import jit
+from pypy.module.micronumpy import support
+from pypy.module.micronumpy.base import W_NDimArray
+
+
+class PureShapeIter(object):
+    def __init__(self, shape, idx_w):
+        self.shape = shape
+        self.shapelen = len(shape)
+        self.indexes = [0] * len(shape)
+        self._done = False
+        self.idx_w = [None] * len(idx_w)
+        for i, w_idx in enumerate(idx_w):
+            if isinstance(w_idx, W_NDimArray):
+                self.idx_w[i] = w_idx.create_iter(shape)
+
+    def done(self):
+        return self._done
+
+    @jit.unroll_safe
+    def next(self):
+        for w_idx in self.idx_w:
+            if w_idx is not None:
+                w_idx.next()
+        for i in range(self.shapelen - 1, -1, -1):
+            if self.indexes[i] < self.shape[i] - 1:
+                self.indexes[i] += 1
+                break
+            else:
+                self.indexes[i] = 0
+        else:
+            self._done = True
+
+    @jit.unroll_safe
+    def get_index(self, space, shapelen):
+        return [space.wrap(self.indexes[i]) for i in range(shapelen)]
+
+
+class ArrayIter(object):
+    _immutable_fields_ = ['array', 'size', 'indices', 'shape[*]',
+                          'strides[*]', 'backstrides[*]']
+
+    def __init__(self, array, size, shape, strides, backstrides):
+        assert len(shape) == len(strides) == len(backstrides)
+        self.array = array
+        self.size = size
+        self.indices = [0] * len(shape)
+        self.shape = shape
+        self.strides = strides
+        self.backstrides = backstrides
+        self.reset()
+
+    @jit.unroll_safe
+    def reset(self):
+        self.index = 0
+        for i in xrange(len(self.shape)):
+            self.indices[i] = 0
+        self.offset = self.array.start
+
+    @jit.unroll_safe
+    def next(self):
+        self.index += 1
+        for i in xrange(len(self.shape) - 1, -1, -1):
+            if self.indices[i] < self.shape[i] - 1:
+                self.indices[i] += 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(len(self.shape) - 1, -1, -1):
+            if self.indices[i] < self.shape[i] - step:
+                self.indices[i] += step
+                self.offset += self.strides[i] * step
+                break
+            else:
+                remaining_step = (self.indices[i] + step) // self.shape[i]
+                this_i_step = step - remaining_step * self.shape[i]
+                self.indices[i] = self.indices[i] + this_i_step
+                self.offset += self.strides[i] * this_i_step
+                step = remaining_step
+                assert step > 0
+
+    def done(self):
+        return self.index >= self.size
+
+    def getitem(self):
+        return self.array.getitem(self.offset)
+
+    def getitem_bool(self):
+        return self.array.getitem_bool(self.offset)
+
+    def setitem(self, elem):
+        self.array.setitem(self.offset, elem)
+
+
+def AxisIter(array, shape, axis, cumulative):
+    strides = array.get_strides()
+    backstrides = array.get_backstrides()
+    if not cumulative:
+        if len(shape) == len(strides):
+            # keepdims = True
+            strides = strides[:axis] + [0] + strides[axis + 1:]
+            backstrides = backstrides[:axis] + [0] + backstrides[axis + 1:]
+        else:
+            strides = strides[:axis] + [0] + strides[axis:]
+            backstrides = backstrides[:axis] + [0] + backstrides[axis:]
+    return ArrayIter(array, support.product(shape), shape, strides, backstrides)
+
+
+def AllButAxisIter(array, axis):
+    size = array.get_size()
+    shape = array.get_shape()[:]
+    backstrides = array.backstrides[:]
+    if size:
+        size /= shape[axis]
+    shape[axis] = backstrides[axis] = 0
+    return ArrayIter(array, size, shape, array.strides, backstrides)
diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py
--- a/pypy/module/micronumpy/loop.py
+++ b/pypy/module/micronumpy/loop.py
@@ -8,7 +8,8 @@
 from rpython.rtyper.lltypesystem import lltype, rffi
 from pypy.module.micronumpy import support, constants as NPY
 from pypy.module.micronumpy.base import W_NDimArray
-from pypy.module.micronumpy.iter import PureShapeIterator
+from pypy.module.micronumpy.iterators import PureShapeIter, AxisIter, \
+    AllButAxisIter
 
 
 call2_driver = jit.JitDriver(name='numpy_call2',
@@ -203,9 +204,9 @@
 
 def do_axis_reduce(space, shape, func, arr, dtype, axis, out, identity, cumulative,
                    temp):
-    out_iter = out.create_axis_iter(arr.get_shape(), axis, cumulative)
+    out_iter = AxisIter(out.implementation, arr.get_shape(), axis, cumulative)
     if cumulative:
-        temp_iter = temp.create_axis_iter(arr.get_shape(), axis, False)
+        temp_iter = AxisIter(temp.implementation, arr.get_shape(), axis, False)
     else:
         temp_iter = out_iter # hack
     arr_iter = arr.create_iter()
@@ -215,16 +216,14 @@
     while not out_iter.done():
         axis_reduce__driver.jit_merge_point(shapelen=shapelen, func=func,
                                             dtype=dtype)
-        if arr_iter.done():
-            w_val = identity
+        assert not arr_iter.done()
+        w_val = arr_iter.getitem().convert_to(space, dtype)
+        if out_iter.indices[axis] == 0:
+            if identity is not None:
+                w_val = func(dtype, identity, w_val)
         else:
-            w_val = arr_iter.getitem().convert_to(space, dtype)
-            if out_iter.first_line:
-                if identity is not None:
-                    w_val = func(dtype, identity, w_val)
-            else:
-                cur = temp_iter.getitem()
-                w_val = func(dtype, cur, w_val)
+            cur = temp_iter.getitem()
+            w_val = func(dtype, cur, w_val)
         out_iter.setitem(w_val)
         if cumulative:
             temp_iter.setitem(w_val)
@@ -261,7 +260,6 @@
 argmin = _new_argmin_argmax('min')
 argmax = _new_argmin_argmax('max')
 
-# note that shapelen == 2 always
 dot_driver = jit.JitDriver(name = 'numpy_dot',
                            greens = ['dtype'],
                            reds = 'auto')
@@ -282,25 +280,27 @@
     '''
     left_shape = left.get_shape()
     right_shape = right.get_shape()
-    broadcast_shape = left_shape[:-1] + right_shape
-    left_skip = [len(left_shape) - 1 + i for i in range(len(right_shape))
-                                         if i != right_critical_dim]
-    right_skip = range(len(left_shape) - 1)
-    result_skip = [len(result.get_shape()) - (len(right_shape) > 1)]
+    assert left_shape[-1] == right_shape[right_critical_dim]
     assert result.get_dtype() == dtype
-    outi = result.create_dot_iter(broadcast_shape, result_skip)
-    lefti = left.create_dot_iter(broadcast_shape, left_skip)
-    righti = right.create_dot_iter(broadcast_shape, right_skip)
-    while not outi.done():
-        dot_driver.jit_merge_point(dtype=dtype)
-        lval = lefti.getitem().convert_to(space, dtype)
-        rval = righti.getitem().convert_to(space, dtype)
-        outval = outi.getitem()
-        v = dtype.itemtype.mul(lval, rval)
-        v = dtype.itemtype.add(v, outval)
-        outi.setitem(v)
-        outi.next()
-        righti.next()
+    outi = result.create_iter()
+    lefti = AllButAxisIter(left.implementation, len(left_shape) - 1)
+    righti = AllButAxisIter(right.implementation, right_critical_dim)
+    while not lefti.done():
+        while not righti.done():
+            oval = outi.getitem()
+            i1 = lefti.offset
+            i2 = righti.offset
+            for _ in xrange(left.implementation.shape[-1]):
+                dot_driver.jit_merge_point(dtype=dtype)
+                lval = left.implementation.getitem(i1).convert_to(space, dtype)
+                rval = right.implementation.getitem(i2).convert_to(space, dtype)
+                oval = dtype.itemtype.add(oval, dtype.itemtype.mul(lval, rval))
+                i1 += left.implementation.strides[-1]
+                i2 += right.implementation.strides[right_critical_dim]
+            outi.setitem(oval)
+            outi.next()
+            righti.next()
+        righti.reset()
         lefti.next()
     return result
 
@@ -478,7 +478,7 @@
     prefixlen = len(prefix_w)
     indexlen = len(indexes_w)
     dtype = arr.get_dtype()
-    iter = PureShapeIterator(iter_shape, indexes_w)
+    iter = PureShapeIter(iter_shape, indexes_w)
     indexlen = len(indexes_w)
     while not iter.done():
         getitem_int_driver.jit_merge_point(shapelen=shapelen, indexlen=indexlen,
@@ -507,7 +507,7 @@
     indexlen = len(indexes_w)
     prefixlen = len(prefix_w)
     dtype = arr.get_dtype()
-    iter = PureShapeIterator(iter_shape, indexes_w)
+    iter = PureShapeIter(iter_shape, indexes_w)
     while not iter.done():
         setitem_int_driver.jit_merge_point(shapelen=shapelen, indexlen=indexlen,
                                            dtype=dtype, prefixlen=prefixlen)
@@ -632,7 +632,7 @@
 
 def diagonal_array(space, arr, out, offset, axis1, axis2, shape):
     out_iter = out.create_iter()
-    iter = PureShapeIterator(shape, [])
+    iter = PureShapeIter(shape, [])
     shapelen_minus_1 = len(shape) - 1
     assert shapelen_minus_1 >= 0
     if axis1 < axis2:
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
@@ -286,12 +286,6 @@
         return self.implementation.create_iter(
             shape=shape, backward_broadcast=backward_broadcast)
 
-    def create_axis_iter(self, shape, dim, cum):
-        return self.implementation.create_axis_iter(shape, dim, cum)
-
-    def create_dot_iter(self, shape, skip):
-        return self.implementation.create_dot_iter(shape, skip)
-
     def is_scalar(self):
         return len(self.get_shape()) == 0
 
diff --git a/pypy/module/micronumpy/sort.py b/pypy/module/micronumpy/sort.py
--- a/pypy/module/micronumpy/sort.py
+++ b/pypy/module/micronumpy/sort.py
@@ -1,6 +1,3 @@
-""" This is the implementation of various sorting routines in numpy. It's here
-because it only makes sense on a concrete array
-"""
 from pypy.interpreter.error import OperationError, oefmt
 from rpython.rlib.listsort import make_timsort_class
 from rpython.rlib.objectmodel import specialize
@@ -11,10 +8,15 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.micronumpy import descriptor, types, constants as NPY
 from pypy.module.micronumpy.base import W_NDimArray
-from pypy.module.micronumpy.iter import AxisIterator
+from pypy.module.micronumpy.iterators import AllButAxisIter
 
 INT_SIZE = rffi.sizeof(lltype.Signed)
 
+all_types = (types.all_float_types + types.all_complex_types +
+             types.all_int_types)
+all_types = [i for i in all_types if not issubclass(i[0], types.Float16)]
+all_types = unrolling_iterable(all_types)
+
 
 def make_argsort_function(space, itemtype, comp_type, count=1):
     TP = itemtype.T
@@ -146,21 +148,20 @@
             if axis < 0 or axis >= len(shape):
                 raise OperationError(space.w_IndexError, space.wrap(
                                                     "Wrong axis %d" % axis))
-            iterable_shape = shape[:axis] + [0] + shape[axis + 1:]
-            iter = AxisIterator(arr, iterable_shape, axis, False)
+            arr_iter = AllButAxisIter(arr, axis)
             index_impl = index_arr.implementation
-            index_iter = AxisIterator(index_impl, iterable_shape, axis, False)
+            index_iter = AllButAxisIter(index_impl, axis)
             stride_size = arr.strides[axis]
             index_stride_size = index_impl.strides[axis]
             axis_size = arr.shape[axis]
-            while not iter.done():
+            while not arr_iter.done():
                 for i in range(axis_size):
                     raw_storage_setitem(storage, i * index_stride_size +
                                         index_iter.offset, i)
                 r = Repr(index_stride_size, stride_size, axis_size,
-                         arr.get_storage(), storage, index_iter.offset, iter.offset)
+                         arr.get_storage(), storage, index_iter.offset, arr_iter.offset)
                 ArgSort(r).sort()
-                iter.next()
+                arr_iter.next()
                 index_iter.next()
         return index_arr
 
@@ -292,14 +293,13 @@
             if axis < 0 or axis >= len(shape):
                 raise OperationError(space.w_IndexError, space.wrap(
                                                     "Wrong axis %d" % axis))
-            iterable_shape = shape[:axis] + [0] + shape[axis + 1:]
-            iter = AxisIterator(arr, iterable_shape, axis, False)
+            arr_iter = AllButAxisIter(arr, axis)
             stride_size = arr.strides[axis]
             axis_size = arr.shape[axis]
-            while not iter.done():
-                r = Repr(stride_size, axis_size, arr.get_storage(), iter.offset)
+            while not arr_iter.done():
+                r = Repr(stride_size, axis_size, arr.get_storage(), arr_iter.offset)
                 ArgSort(r).sort()
-                iter.next()
+                arr_iter.next()
 
     return sort
 
@@ -319,11 +319,6 @@
                 "sorting of non-numeric types '%s' is not implemented",
                 arr.dtype.get_name())
 
-all_types = (types.all_float_types + types.all_complex_types +
-             types.all_int_types)
-all_types = [i for i in all_types if not issubclass(i[0], types.Float16)]
-all_types = unrolling_iterable(all_types)
-
 
 class ArgSortCache(object):
     built = False
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
@@ -421,18 +421,3 @@
                     n_old_elems_to_use *= old_shape[oldI]
     assert len(new_strides) == len(new_shape)
     return new_strides[:]
-
-
-def calculate_dot_strides(strides, backstrides, res_shape, skip_dims):
-    rstrides = [0] * len(res_shape)
-    rbackstrides = [0] * len(res_shape)
-    j = 0
-    for i in range(len(res_shape)):
-        if i in skip_dims:
-            rstrides[i] = 0
-            rbackstrides[i] = 0
-        else:
-            rstrides[i] = strides[j]
-            rbackstrides[i] = backstrides[j]
-            j += 1
-    return rstrides, rbackstrides
diff --git a/pypy/module/micronumpy/test/test_arrayops.py b/pypy/module/micronumpy/test/test_arrayops.py
--- a/pypy/module/micronumpy/test/test_arrayops.py
+++ b/pypy/module/micronumpy/test/test_arrayops.py
@@ -41,8 +41,7 @@
         a[0] = 0
         assert (b == [1, 1, 1, 0, 0]).all()
 
-
-    def test_dot(self):
+    def test_dot_basic(self):
         from numpypy import array, dot, arange
         a = array(range(5))
         assert dot(a, a) == 30.0
@@ -69,7 +68,7 @@
         assert b.shape == (4, 3)
         c = dot(a, b)
         assert (c == [[[14, 38, 62], [38, 126, 214], [62, 214, 366]],
-                   [[86, 302, 518], [110, 390, 670], [134, 478, 822]]]).all()
+                      [[86, 302, 518], [110, 390, 670], [134, 478, 822]]]).all()
         c = dot(a, b[:, 2])
         assert (c == [[62, 214, 366], [518, 670, 822]]).all()
         a = arange(3*2*6).reshape((3,2,6))
diff --git a/pypy/module/micronumpy/test/test_iter.py b/pypy/module/micronumpy/test/test_iter.py
deleted file mode 100644
--- a/pypy/module/micronumpy/test/test_iter.py
+++ /dev/null
@@ -1,93 +0,0 @@
-from pypy.module.micronumpy.iter import MultiDimViewIterator
-
-
-class MockArray(object):
-    size = 1
-
-
-class TestIterDirect(object):
-    def test_C_viewiterator(self):
-        #Let's get started, simple iteration in C order with
-        #contiguous layout => strides[-1] is 1
-        start = 0
-        shape = [3, 5]
-        strides = [5, 1]
-        backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
-        assert backstrides == [10, 4]
-        i = MultiDimViewIterator(MockArray, start, strides, backstrides, shape)
-        i.next()
-        i.next()
-        i.next()
-        assert i.offset == 3
-        assert not i.done()
-        assert i.indexes == [0,3]
-        #cause a dimension overflow
-        i.next()
-        i.next()
-        assert i.offset == 5
-        assert i.indexes == [1,0]
-
-        #Now what happens if the array is transposed? strides[-1] != 1
-        # therefore layout is non-contiguous
-        strides = [1, 3]
-        backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
-        assert backstrides == [2, 12]
-        i = MultiDimViewIterator(MockArray, start, strides, backstrides, shape)
-        i.next()
-        i.next()
-        i.next()
-        assert i.offset == 9
-        assert not i.done()
-        assert i.indexes == [0,3]
-        #cause a dimension overflow
-        i.next()
-        i.next()
-        assert i.offset == 1
-        assert i.indexes == [1,0]
-
-    def test_C_viewiterator_step(self):
-        #iteration in C order with #contiguous layout => strides[-1] is 1
-        #skip less than the shape
-        start = 0
-        shape = [3, 5]
-        strides = [5, 1]
-        backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
-        assert backstrides == [10, 4]
-        i = MultiDimViewIterator(MockArray, start, strides, backstrides, shape)
-        i.next_skip_x(2)
-        i.next_skip_x(2)
-        i.next_skip_x(2)
-        assert i.offset == 6
-        assert not i.done()
-        assert i.indexes == [1,1]
-        #And for some big skips
-        i.next_skip_x(5)
-        assert i.offset == 11
-        assert i.indexes == [2,1]
-        i.next_skip_x(5)
-        # Note: the offset does not overflow but recycles,
-        # this is good for broadcast
-        assert i.offset == 1
-        assert i.indexes == [0,1]
-        assert i.done()
-
-        #Now what happens if the array is transposed? strides[-1] != 1
-        # therefore layout is non-contiguous
-        strides = [1, 3]
-        backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
-        assert backstrides == [2, 12]
-        i = MultiDimViewIterator(MockArray, start, strides, backstrides, shape)
-        i.next_skip_x(2)
-        i.next_skip_x(2)
-        i.next_skip_x(2)
-        assert i.offset == 4
-        assert i.indexes == [1,1]
-        assert not i.done()
-        i.next_skip_x(5)
-        assert i.offset == 5
-        assert i.indexes == [2,1]
-        assert not i.done()
-        i.next_skip_x(5)
-        assert i.indexes == [0,1]
-        assert i.offset == 3
-        assert i.done()
diff --git a/pypy/module/micronumpy/test/test_iterators.py b/pypy/module/micronumpy/test/test_iterators.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_iterators.py
@@ -0,0 +1,96 @@
+from pypy.module.micronumpy import support
+from pypy.module.micronumpy.iterators import ArrayIter
+
+
+class MockArray(object):
+    start = 0
+
+
+class TestIterDirect(object):
+    def test_iterator_basic(self):
+        #Let's get started, simple iteration in C order with
+        #contiguous layout => strides[-1] is 1
+        shape = [3, 5]
+        strides = [5, 1]
+        backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
+        assert backstrides == [10, 4]
+        i = ArrayIter(MockArray, support.product(shape), shape,
+                      strides, backstrides)
+        i.next()
+        i.next()
+        i.next()
+        assert i.offset == 3
+        assert not i.done()
+        assert i.indices == [0,3]
+        #cause a dimension overflow
+        i.next()
+        i.next()
+        assert i.offset == 5
+        assert i.indices == [1,0]
+
+        #Now what happens if the array is transposed? strides[-1] != 1
+        # therefore layout is non-contiguous
+        strides = [1, 3]
+        backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
+        assert backstrides == [2, 12]
+        i = ArrayIter(MockArray, support.product(shape), shape,
+                      strides, backstrides)
+        i.next()
+        i.next()
+        i.next()
+        assert i.offset == 9
+        assert not i.done()
+        assert i.indices == [0,3]
+        #cause a dimension overflow
+        i.next()
+        i.next()
+        assert i.offset == 1
+        assert i.indices == [1,0]
+
+    def test_iterator_step(self):
+        #iteration in C order with #contiguous layout => strides[-1] is 1
+        #skip less than the shape
+        shape = [3, 5]
+        strides = [5, 1]
+        backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
+        assert backstrides == [10, 4]
+        i = ArrayIter(MockArray, support.product(shape), shape,
+                      strides, backstrides)
+        i.next_skip_x(2)
+        i.next_skip_x(2)
+        i.next_skip_x(2)
+        assert i.offset == 6
+        assert not i.done()
+        assert i.indices == [1,1]
+        #And for some big skips
+        i.next_skip_x(5)
+        assert i.offset == 11
+        assert i.indices == [2,1]
+        i.next_skip_x(5)
+        # Note: the offset does not overflow but recycles,
+        # this is good for broadcast
+        assert i.offset == 1
+        assert i.indices == [0,1]
+        assert i.done()
+
+        #Now what happens if the array is transposed? strides[-1] != 1
+        # therefore layout is non-contiguous
+        strides = [1, 3]
+        backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
+        assert backstrides == [2, 12]
+        i = ArrayIter(MockArray, support.product(shape), shape,
+                      strides, backstrides)
+        i.next_skip_x(2)
+        i.next_skip_x(2)
+        i.next_skip_x(2)
+        assert i.offset == 4
+        assert i.indices == [1,1]
+        assert not i.done()
+        i.next_skip_x(5)
+        assert i.offset == 5
+        assert i.indices == [2,1]
+        assert not i.done()
+        i.next_skip_x(5)
+        assert i.indices == [0,1]
+        assert i.offset == 3
+        assert i.done()
diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -1740,10 +1740,11 @@
         a = array([(1, 2)], dtype=[('a', 'int64'), ('b', 'int64')])[0]
         assert a.shape == ()
         assert a.view('S16') == '\x01' + '\x00' * 7 + '\x02'
-        a = array(2, dtype='int64')
-        b = a.view('complex64')
+        a = array(2, dtype='<i8')
+        b = a.view('<c8')
         assert 0 < b.real < 1
-        assert b.imag == 0
+        assert b.real.tostring() == '\x02\x00\x00\x00'
+        assert b.imag.tostring() == '\x00' * 4
 
     def test_array_view(self):
         from numpypy import array, dtype
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
@@ -59,6 +59,7 @@
         if self.graph is None:
             interp, graph = self.meta_interp(f, [0],
                                              listops=True,
+                                             listcomp=True,
                                              backendopt=True,
                                              graph_and_interp_only=True)
             self.__class__.interp = interp
@@ -69,7 +70,6 @@
         reset_jit()
         i = self.code_mapping[name]
         retval = self.interp.eval_graph(self.graph, [i])
-        py.test.skip("don't run for now")
         return retval
 
     def define_add():
@@ -81,6 +81,7 @@
 
     def test_add(self):
         result = self.run("add")
+        py.test.skip("don't run for now")
         self.check_simple_loop({'raw_load': 2, 'float_add': 1,
                                 'raw_store': 1, 'int_add': 1,
                                 'int_ge': 1, 'guard_false': 1, 'jump': 1,
@@ -96,6 +97,7 @@
     def test_floatadd(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,
@@ -111,6 +113,7 @@
     def test_sum(self):
         result = self.run("sum")
         assert result == 2 * sum(range(30))
+        py.test.skip("don't run for now")
         self.check_simple_loop({"raw_load": 2, "float_add": 2,
                                 "int_add": 1, "int_ge": 1, "guard_false": 1,
                                 "jump": 1, 'arraylen_gc': 1})
@@ -125,6 +128,7 @@
     def test_axissum(self):
         result = self.run("axissum")
         assert result == 30
+        py.test.skip("don't run for now")
         # XXX note - the bridge here is fairly crucial and yet it's pretty
         #            bogus. We need to improve the situation somehow.
         self.check_simple_loop({'raw_load': 2,
@@ -177,6 +181,7 @@
         for i in range(30):
             expected *= i * 2
         assert result == expected
+        py.test.skip("don't run for now")
         self.check_simple_loop({"raw_load": 2, "float_add": 1,
                                 "float_mul": 1, "int_add": 1,
                                 "int_ge": 1, "guard_false": 1, "jump": 1,
@@ -222,6 +227,7 @@
     def test_any(self):
         result = self.run("any")
         assert result == 1
+        py.test.skip("don't run for now")
         self.check_simple_loop({"raw_load": 2, "float_add": 1,
                                 "int_and": 1, "int_add": 1,
                                 'cast_float_to_int': 1,
@@ -263,6 +269,7 @@
     def test_ufunc(self):
         result = self.run("ufunc")
         assert result == -6
+        py.test.skip("don't run for now")
         self.check_simple_loop({"raw_load": 2, "float_add": 1,
                                 "float_neg": 1,
                                 "raw_store": 1, "int_add": 1,
@@ -291,6 +298,7 @@
 
     def test_specialization(self):
         self.run("specialization")
+        py.test.skip("don't run for now")
         # This is 3, not 2 because there is a bridge for the exit.
         self.check_trace_count(3)
 
@@ -305,6 +313,7 @@
     def test_slice(self):
         result = self.run("slice")
         assert result == 18
+        py.test.skip("don't run for now")
         self.check_simple_loop({'raw_load': 2,
                                 'float_add': 1,
                                 'raw_store': 1,
@@ -345,6 +354,7 @@
     def test_multidim(self):
         result = self.run('multidim')
         assert result == 8
+        py.test.skip("don't run for now")
         # int_add might be 1 here if we try slightly harder with
         # reusing indexes or some optimization
         self.check_simple_loop({'float_add': 1, 'raw_load': 2,
@@ -395,6 +405,7 @@
     def test_setslice(self):
         result = self.run("setslice")
         assert result == 11.0
+        py.test.skip("don't run for now")
         self.check_trace_count(1)
         self.check_simple_loop({'raw_load': 2, 'float_add': 1,
                                 'raw_store': 1, 'int_add': 2,
@@ -412,6 +423,7 @@
     def test_virtual_slice(self):
         result = self.run("virtual_slice")
         assert result == 4
+        py.test.skip("don't run for now")
         self.check_trace_count(1)
         self.check_simple_loop({'raw_load': 2, 'float_add': 1,
                                 'raw_store': 1, 'int_add': 1,
@@ -428,6 +440,7 @@
     def test_flat_iter(self):
         result = self.run("flat_iter")
         assert result == 6
+        py.test.skip("don't run for now")
         self.check_trace_count(1)
         self.check_simple_loop({'raw_load': 2, 'float_add': 1,
                                 'raw_store': 1, 'int_add': 2,
@@ -444,6 +457,7 @@
     def test_flat_getitem(self):
         result = self.run("flat_getitem")
         assert result == 10.0
+        py.test.skip("don't run for now")
         self.check_trace_count(1)
         self.check_simple_loop({'raw_load': 1,
                                 'raw_store': 1,
@@ -466,6 +480,7 @@
     def test_flat_setitem(self):
         result = self.run("flat_setitem")
         assert result == 1.0
+        py.test.skip("don't run for now")
         self.check_trace_count(1)
         # XXX not ideal, but hey, let's ignore it for now
         self.check_simple_loop({'raw_load': 1,
@@ -494,18 +509,40 @@
     def test_dot(self):
         result = self.run("dot")
         assert result == 184
-        self.check_simple_loop({'arraylen_gc': 9,
-                                'float_add': 1,
+        self.check_simple_loop({'float_add': 1,
                                 'float_mul': 1,
-                                'raw_load': 3,
-                                'guard_false': 3,
-                                'guard_true': 3,
-                                'int_add': 6,
-                                'int_lt': 6,
-                                'int_sub': 3,
+                                'guard_not_invalidated': 1,
+                                'guard_false': 1,
+                                'int_add': 3,
+                                'int_ge': 1,
                                 'jump': 1,
-                                'raw_store': 1})
-    
+                                'raw_load': 2,
+                                'setfield_gc': 1})
+        self.check_resops({'arraylen_gc': 4,
+                           'float_add': 2,
+                           'float_mul': 2,
+                           'getarrayitem_gc': 11,
+                           'getarrayitem_gc_pure': 15,
+                           'getfield_gc': 26,
+                           'getfield_gc_pure': 32,
+                           'guard_class': 4,
+                           'guard_false': 18,
+                           'guard_not_invalidated': 2,
+                           'guard_true': 9,
+                           'int_add': 25,
+                           'int_ge': 8,
+                           'int_le': 8,
+                           'int_lt': 7,
+                           'int_sub': 15,
+                           'jump': 3,
+                           'new': 1,
+                           'new_with_vtable': 1,
+                           'raw_load': 6,
+                           'raw_store': 1,
+                           'same_as': 2,
+                           'setarrayitem_gc': 10,
+                           'setfield_gc': 19})
+
     def define_argsort():
         return """
         a = |30|
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -164,13 +164,13 @@
     def reduce(self, space, w_obj, w_axis, keepdims=False, out=None, dtype=None,
                cumulative=False):
         if self.argcount != 2:
-            raise OperationError(space.w_ValueError, space.wrap("reduce only "
-                "supported for binary functions"))
+            raise oefmt(space.w_ValueError,
+                        "reduce only supported for binary functions")
         assert isinstance(self, W_Ufunc2)
         obj = convert_to_array(space, w_obj)
         if obj.get_dtype().is_flexible():
-            raise OperationError(space.w_TypeError,
-                      space.wrap('cannot perform reduce with flexible type'))
+            raise oefmt(space.w_TypeError,
+                        "cannot perform reduce with flexible type")
         obj_shape = obj.get_shape()
         if obj.is_scalar():
             return obj.get_scalar_value()
@@ -210,7 +210,7 @@
                 if out:
                     dtype = out.get_dtype()
                 temp = W_NDimArray.from_shape(space, temp_shape, dtype,
-                                                w_instance=obj)
+                                              w_instance=obj)
             elif keepdims:
                 shape = obj_shape[:axis] + [1] + obj_shape[axis + 1:]
             else:
@@ -236,21 +236,28 @@
                                 )
                 dtype = out.get_dtype()
             else:
-                out = W_NDimArray.from_shape(space, shape, dtype, w_instance=obj)
-            return loop.do_axis_reduce(space, shape, self.func, obj, dtype, axis, out,
-                                       self.identity, cumulative, temp)
+                out = W_NDimArray.from_shape(space, shape, dtype,
+                                             w_instance=obj)
+            if obj.get_size() == 0:
+                if self.identity is not None:
+                    out.fill(space, self.identity.convert_to(space, dtype))
+                return out
+            return loop.do_axis_reduce(space, shape, self.func, obj, dtype,
+                                       axis, out, self.identity, cumulative,
+                                       temp)
         if cumulative:
             if out:
                 if out.get_shape() != [obj.get_size()]:
                     raise OperationError(space.w_ValueError, space.wrap(
                         "out of incompatible size"))
             else:
-                out = W_NDimArray.from_shape(space, [obj.get_size()], dtype, w_instance=obj)
+                out = W_NDimArray.from_shape(space, [obj.get_size()], dtype,
+                                             w_instance=obj)
             loop.compute_reduce_cumulative(space, obj, out, dtype, self.func,
-                                            self.identity)
+                                           self.identity)
             return out
         if out:
-            if len(out.get_shape())>0:
+            if len(out.get_shape()) > 0:
                 raise oefmt(space.w_ValueError,
                             "output parameter for reduction operation %s has "
                             "too many dimensions", self.name)
@@ -262,7 +269,8 @@
             return out
         if keepdims:
             shape = [1] * len(obj_shape)
-            out = W_NDimArray.from_shape(space, [1] * len(obj_shape), dtype, w_instance=obj)
+            out = W_NDimArray.from_shape(space, [1] * len(obj_shape), dtype,
+                                         w_instance=obj)
             out.implementation.setitem(0, res)
             return out
         return res
@@ -274,6 +282,7 @@
         raise OperationError(space.w_ValueError, space.wrap(
             "outer product only supported for binary functions"))
 
+
 class W_Ufunc1(W_Ufunc):
     _immutable_fields_ = ["func", "bool_result"]
     argcount = 1
diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py
--- a/rpython/rlib/entrypoint.py
+++ b/rpython/rlib/entrypoint.py
@@ -78,7 +78,8 @@
 # registered
 
 RPython_StartupCode = rffi.llexternal('RPython_StartupCode', [], lltype.Void,
-                                      _nowrapper=True)
+                                      _nowrapper=True,
+                                      random_effects_on_gcobjs=True)
 
 @entrypoint('main', [], c_name='rpython_startup_code')
 def rpython_startup_code():


More information about the pypy-commit mailing list