[pypy-commit] pypy win64-stage1: merge default

ctismer noreply at buildbot.pypy.org
Tue Dec 6 17:40:32 CET 2011


Author: Christian Tismer <tismer at stackless.com>
Branch: win64-stage1
Changeset: r50213:b853ad20830d
Date: 2011-12-06 17:39 +0100
http://bitbucket.org/pypy/pypy/changeset/b853ad20830d/

Log:	merge default

diff --git a/lib_pypy/_collections.py b/lib_pypy/_collections.py
--- a/lib_pypy/_collections.py
+++ b/lib_pypy/_collections.py
@@ -379,12 +379,14 @@
 class defaultdict(dict):
     
     def __init__(self, *args, **kwds):
-        self.default_factory = None
-        if 'default_factory' in kwds:
-            self.default_factory = kwds.pop('default_factory')
-        elif len(args) > 0 and (callable(args[0]) or args[0] is None):
-            self.default_factory = args[0]
+        if len(args) > 0:
+            default_factory = args[0]
             args = args[1:]
+            if not callable(default_factory) and default_factory is not None:
+                raise TypeError("first argument must be callable")
+        else:
+            default_factory = None
+        self.default_factory = default_factory
         super(defaultdict, self).__init__(*args, **kwds)
  
     def __missing__(self, key):
diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -823,6 +823,15 @@
                                             bool(v.value)): # store a non-NULL
                         self._gen_write_barrier(newops, op.getarg(0), v)
                         op = op.copy_and_change(rop.SETFIELD_RAW)
+            # ---------- write barrier for SETINTERIORFIELD_GC ------
+            if op.getopnum() == rop.SETINTERIORFIELD_GC:
+                val = op.getarg(0)
+                if val is not last_malloc:
+                    v = op.getarg(2)
+                    if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
+                                            bool(v.value)): # store a non-NULL
+                        self._gen_write_barrier(newops, op.getarg(0), v)
+                        op = op.copy_and_change(rop.SETINTERIORFIELD_RAW)
             # ---------- write barrier for SETARRAYITEM_GC ----------
             if op.getopnum() == rop.SETARRAYITEM_GC:
                 val = op.getarg(0)
diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py
--- a/pypy/jit/backend/llsupport/test/test_gc.py
+++ b/pypy/jit/backend/llsupport/test/test_gc.py
@@ -571,6 +571,28 @@
             assert operations[1].getarg(2) == v_value
             assert operations[1].getdescr() == array_descr
 
+    def test_rewrite_assembler_5(self):
+        S = lltype.GcStruct('S')
+        A = lltype.GcArray(lltype.Struct('A', ('x', lltype.Ptr(S))))
+        interiordescr = get_interiorfield_descr(self.gc_ll_descr, A,
+                                                A.OF, 'x')
+        wbdescr = self.gc_ll_descr.write_barrier_descr
+        ops = parse("""
+        [p1, p2]
+        setinteriorfield_gc(p1, 0, p2, descr=interiordescr)
+        jump(p1, p2)
+        """, namespace=locals())
+        expected = parse(""" 
+        [p1, p2]
+        cond_call_gc_wb(p1, p2, descr=wbdescr)
+        setinteriorfield_raw(p1, 0, p2, descr=interiordescr)
+        jump(p1, p2)
+        """, namespace=locals())
+        operations = get_deep_immutable_oplist(ops.operations)
+        operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu,
+                                                        operations, [])
+        equaloplists(operations, expected.operations)
+
     def test_rewrite_assembler_initialization_store(self):
         S = lltype.GcStruct('S', ('parent', OBJECT),
                             ('x', lltype.Signed))
diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py
--- a/pypy/jit/backend/x86/test/test_zrpy_gc.py
+++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py
@@ -490,8 +490,8 @@
                 check(a[i].y.i == n + i * 100 + 2)
                 check(a[i].z.i == n + i * 100 + 3)
                 i += 1
+            n -= x.foo
             return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s
-        f(123, *[None]*11)  # check that the check() are ok
         return None, f, None
 
     def test_compile_framework_7_interior(self):
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -298,7 +298,7 @@
     pass
 
 class ResumeGuardDescr(ResumeDescr):
-    _counter = 0        # if < 0, there is one counter per value;
+    _counter = 0        # on a GUARD_VALUE, there is one counter per value;
     _counters = None    # they get stored in _counters then.
 
     # this class also gets the following attributes stored by resume.py code
@@ -309,10 +309,13 @@
     rd_virtuals = None
     rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO)
 
-    CNT_INT   = -0x20000000
-    CNT_REF   = -0x40000000
-    CNT_FLOAT = -0x60000000
-    CNT_MASK  =  0x1FFFFFFF
+    CNT_BASE_MASK  =  0x0FFFFFFF     # the base counter value
+    CNT_BUSY_FLAG  =  0x10000000     # if set, busy tracing from the guard
+    CNT_TYPE_MASK  =  0x60000000     # mask for the type
+
+    CNT_INT        =  0x20000000
+    CNT_REF        =  0x40000000
+    CNT_FLOAT      =  0x60000000
 
     def store_final_boxes(self, guard_op, boxes):
         guard_op.setfailargs(boxes)
@@ -326,6 +329,8 @@
         except ValueError:
             return     # xxx probably very rare
         else:
+            if i > self.CNT_BASE_MASK:
+                return    # probably never, but better safe than sorry
             if box.type == history.INT:
                 cnt = self.CNT_INT
             elif box.type == history.REF:
@@ -334,14 +339,17 @@
                 cnt = self.CNT_FLOAT
             else:
                 assert 0, box.type
-            # we build the following value for _counter, which is always
-            # a negative value
+            assert cnt > self.CNT_BASE_MASK
             self._counter = cnt | i
 
     def handle_fail(self, metainterp_sd, jitdriver_sd):
         if self.must_compile(metainterp_sd, jitdriver_sd):
-            return self._trace_and_compile_from_bridge(metainterp_sd,
-                                                       jitdriver_sd)
+            self.start_compiling()
+            try:
+                return self._trace_and_compile_from_bridge(metainterp_sd,
+                                                           jitdriver_sd)
+            finally:
+                self.done_compiling()
         else:
             from pypy.jit.metainterp.blackhole import resume_in_blackhole
             resume_in_blackhole(metainterp_sd, jitdriver_sd, self)
@@ -359,12 +367,22 @@
 
     def must_compile(self, metainterp_sd, jitdriver_sd):
         trace_eagerness = jitdriver_sd.warmstate.trace_eagerness
-        if self._counter >= 0:
+        #
+        if self._counter <= self.CNT_BASE_MASK:
+            # simple case: just counting from 0 to trace_eagerness
             self._counter += 1
             return self._counter >= trace_eagerness
-        else:
-            index = self._counter & self.CNT_MASK
-            typetag = self._counter & ~ self.CNT_MASK
+        #
+        # do we have the BUSY flag?  If so, we're tracing right now, e.g. in an
+        # outer invocation of the same function, so don't trace again for now.
+        elif self._counter & self.CNT_BUSY_FLAG:
+            return False
+        #
+        else: # we have a GUARD_VALUE that fails.  Make a _counters instance
+            # (only now, when the guard is actually failing at least once),
+            # and use it to record some statistics about the failing values.
+            index = self._counter & self.CNT_BASE_MASK
+            typetag = self._counter & self.CNT_TYPE_MASK
             counters = self._counters
             if typetag == self.CNT_INT:
                 intvalue = metainterp_sd.cpu.get_latest_value_int(index)
@@ -391,7 +409,16 @@
                 assert 0, typetag
             return counter >= trace_eagerness
 
-    def reset_counter_from_failure(self):
+    def start_compiling(self):
+        # start tracing and compiling from this guard.
+        self._counter |= self.CNT_BUSY_FLAG
+
+    def done_compiling(self):
+        # done tracing and compiling from this guard.  Either the bridge has
+        # been successfully compiled, in which case whatever value we store
+        # in self._counter will not be seen any more, or not, in which case
+        # we should reset the counter to 0, in order to wait a bit until the
+        # next attempt.
         if self._counter >= 0:
             self._counter = 0
         self._counters = None
@@ -608,9 +635,6 @@
         metainterp.set_compiled_merge_points(self.original_greenkey,
                                              old_loop_tokens)
 
-    def reset_counter_from_failure(self):
-        pass
-
 
 def compile_new_bridge(metainterp, old_loop_tokens, resumekey, retraced=False):
     """Try to compile a new bridge leading from the beginning of the history
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -1790,7 +1790,6 @@
         self.staticdata.profiler.count(reason)
         debug_print('~~~ ABORTING TRACING')
         self.staticdata.stats.aborted()
-        self.resumekey.reset_counter_from_failure()
 
     def blackhole_if_trace_too_long(self):
         warmrunnerstate = self.jitdriver_sd.warmstate
diff --git a/pypy/jit/metainterp/test/test_math.py b/pypy/jit/metainterp/test/test_math.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/test/test_math.py
@@ -0,0 +1,47 @@
+import math
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
+from pypy.rlib.rfloat import isinf, isnan, INFINITY, NAN
+
+class MathTests:
+    
+    def test_math_sqrt(self):
+        def f(x):
+            try:
+                return math.sqrt(x)
+            except ValueError:
+                return -INFINITY
+        
+        res = self.interp_operations(f, [0.0])
+        assert res == 0.0
+        self.check_operations_history(call_pure=1)
+        #
+        res = self.interp_operations(f, [25.0])
+        assert res == 5.0
+        self.check_operations_history(call_pure=1)
+        #
+        res = self.interp_operations(f, [-0.0])
+        assert str(res) == '-0.0'
+        self.check_operations_history(call_pure=1)
+        #
+        res = self.interp_operations(f, [1000000.0])
+        assert res == 1000.0
+        self.check_operations_history(call_pure=1)
+        #
+        res = self.interp_operations(f, [-1.0])
+        assert res == -INFINITY
+        self.check_operations_history(call_pure=0)
+        #
+        res = self.interp_operations(f, [INFINITY])
+        assert isinf(res) and not isnan(res) and res > 0.0
+        self.check_operations_history(call_pure=0)
+        #
+        res = self.interp_operations(f, [NAN])
+        assert isnan(res) and not isinf(res)
+        self.check_operations_history(call_pure=0)
+
+
+class TestOOtype(MathTests, OOJitMixin):
+    pass
+
+class TestLLtype(MathTests, LLJitMixin):
+    pass
diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py
--- a/pypy/jit/metainterp/test/test_recursive.py
+++ b/pypy/jit/metainterp/test/test_recursive.py
@@ -1238,6 +1238,31 @@
         self.meta_interp(portal, [0, 0, 0], inline=True)
         self.check_resops(call_may_force=0, call=0)
 
+    def test_dont_repeatedly_trace_from_the_same_guard(self):
+        driver = JitDriver(greens = [], reds = ['level', 'i'])
+
+        def portal(level):
+            if level == 0:
+                i = -10
+            else:
+                i = 0
+            #
+            while True:
+                driver.jit_merge_point(level=level, i=i)
+                if level == 25:
+                    return 42
+                i += 1
+                if i <= 0:      # <- guard
+                    continue    # first make a loop
+                else:
+                    # then we fail the guard above, doing a recursive call,
+                    # which will itself fail the same guard above, and so on
+                    return portal(level + 1)
+
+        self.meta_interp(portal, [0])
+        self.check_loop_count_at_most(2)   # and not, e.g., 24
+
+
 class TestLLtype(RecursiveTests, LLJitMixin):
     pass
 
diff --git a/pypy/module/_collections/app_defaultdict.py b/pypy/module/_collections/app_defaultdict.py
--- a/pypy/module/_collections/app_defaultdict.py
+++ b/pypy/module/_collections/app_defaultdict.py
@@ -13,12 +13,14 @@
 class defaultdict(dict):
     
     def __init__(self, *args, **kwds):
-        self.default_factory = None
-        if 'default_factory' in kwds:
-            self.default_factory = kwds.pop('default_factory')
-        elif len(args) > 0 and (callable(args[0]) or args[0] is None):
-            self.default_factory = args[0]
+        if len(args) > 0:
+            default_factory = args[0]
             args = args[1:]
+            if not callable(default_factory) and default_factory is not None:
+                raise TypeError("first argument must be callable")
+        else:
+            default_factory = None
+        self.default_factory = default_factory
         super(defaultdict, self).__init__(*args, **kwds)
  
     def __missing__(self, key):
diff --git a/pypy/module/_collections/test/test_defaultdict.py b/pypy/module/_collections/test/test_defaultdict.py
--- a/pypy/module/_collections/test/test_defaultdict.py
+++ b/pypy/module/_collections/test/test_defaultdict.py
@@ -19,11 +19,22 @@
 
     def test_keyerror_without_factory(self):
         from _collections import defaultdict
-        d1 = defaultdict()
-        for key in ['foo', (1,)]:
-            try:
-                d1[key]
-            except KeyError, err:
-                assert err.args[0] == key
-            else:
-                assert 0, "expected KeyError"
+        for d1 in [defaultdict(), defaultdict(None)]:
+            for key in ['foo', (1,)]:
+                try:
+                    d1[key]
+                except KeyError, err:
+                    assert err.args[0] == key
+                else:
+                    assert 0, "expected KeyError"
+
+    def test_noncallable(self):
+        from _collections import defaultdict
+        raises(TypeError, defaultdict, [('a', 5)])
+        d = defaultdict(None, [('a', 5)])
+        assert d.items() == [('a', 5)]
+
+    def test_kwds(self):
+        from _collections import defaultdict
+        d = defaultdict(default_factory=5)
+        assert d.keys() == ['default_factory']
diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py
--- a/pypy/module/_socket/interp_func.py
+++ b/pypy/module/_socket/interp_func.py
@@ -1,7 +1,7 @@
 from pypy.interpreter.gateway import unwrap_spec
 from pypy.module._socket.interp_socket import converted_error, W_RSocket
 from pypy.rlib import rsocket
-from pypy.rlib.rsocket import SocketError
+from pypy.rlib.rsocket import SocketError, INVALID_SOCKET
 from pypy.interpreter.error import OperationError
 
 def gethostname(space):
@@ -284,7 +284,7 @@
                             space.wrap(socktype),
                             space.wrap(protocol),
                             space.wrap(canonname),
-                            addr.as_object(-1, space)]) # -1 as per cpython
+                            addr.as_object(INVALID_SOCKET, space)]) # -1 as per cpython
             for (family, socktype, protocol, canonname, addr) in lst]
     return space.newlist(lst1)
 
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
@@ -32,6 +32,7 @@
         'int_': 'interp_boxes.W_LongBox',
         'inexact': 'interp_boxes.W_InexactBox',
         'floating': 'interp_boxes.W_FloatingBox',
+        'float32': 'interp_boxes.W_Float32Box',
         'float64': 'interp_boxes.W_Float64Box',
     }
 
@@ -76,4 +77,5 @@
         'inf': 'app_numpy.inf',
         'e': 'app_numpy.e',
         'arange': 'app_numpy.arange',
+        'reshape': 'app_numpy.reshape',
     }
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
@@ -36,3 +36,39 @@
         j += 1
         i += step
     return arr
+
+def reshape(a, shape):
+    '''reshape(a, newshape)
+    Gives a new shape to an array without changing its data.
+    
+    Parameters
+    ----------
+    a : array_like
+        Array to be reshaped.
+    newshape : int or tuple of ints
+        The new shape should be compatible with the original shape. If
+        an integer, then the result will be a 1-D array of that length.
+        One shape dimension can be -1. In this case, the value is inferred
+        from the length of the array and remaining dimensions.
+    
+    Returns
+    -------
+    reshaped_array : ndarray
+        This will be a new view object if possible; otherwise, it will
+        be a copy.
+    
+    
+    See Also
+    --------
+    ndarray.reshape : Equivalent method.
+    
+    Notes
+    -----
+    
+    It is not always possible to change the shape of an array without
+    copying the data. If you want an error to be raise if the data is copied,
+    you should assign the new shape to the shape attribute of the array
+'''
+    if not hasattr(a, 'reshape'):
+        a = numpypy.array(a)
+    return a.reshape(shape)
diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py
--- a/pypy/module/micronumpy/interp_boxes.py
+++ b/pypy/module/micronumpy/interp_boxes.py
@@ -258,6 +258,8 @@
 
 W_Float32Box.typedef = TypeDef("float32", W_FloatingBox.typedef,
     __module__ = "numpypy",
+
+    __new__ = interp2app(W_Float32Box.descr__new__.im_func),
 )
 
 W_Float64Box.typedef = TypeDef("float64", (W_FloatingBox.typedef, float_typedef),
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -98,6 +98,107 @@
         endshape[i] = remainder[i]
     return endshape
 
+def get_shape_from_iterable(space, old_size, w_iterable):
+    new_size = 0
+    new_shape = []
+    if space.isinstance_w(w_iterable, space.w_int):
+        new_size = space.int_w(w_iterable)
+        if new_size < 0:
+            new_size = old_size
+        new_shape = [new_size, ]
+    else:
+        neg_dim = -1
+        batch = space.listview(w_iterable)
+        #Allow for shape = (1,2,3) or shape = ((1,2,3))
+        if len(batch) > 1 and space.issequence_w(batch[0]):
+            batch = space.listview(batch[0])
+        new_size = 1
+        if len(batch) < 1:
+            if old_size == 1:
+                #Scalars can have an empty size.
+                new_size = 1
+            else:
+                new_size = 0
+        new_shape = []
+        i = 0
+        for elem in batch:
+            s = space.int_w(elem)
+            if s < 0:
+                if neg_dim >= 0:
+                    raise OperationError(space.w_ValueError, space.wrap(
+                             "can only specify one unknown dimension"))
+                s = 1
+                neg_dim = i
+            new_size *= s
+            new_shape.append(s)
+            i += 1
+        if neg_dim >= 0:
+            new_shape[neg_dim] = old_size / new_size
+            new_size *= new_shape[neg_dim]
+    if new_size != old_size:
+        raise OperationError(space.w_ValueError,
+                space.wrap("total size of new array must be unchanged"))
+    return new_shape
+
+#Recalculating strides. Find the steps that the iteration does for each
+#dimension, given the stride and shape. Then try to create a new stride that
+#fits the new shape, using those steps. If there is a shape/step mismatch
+#(meaning that the realignment of elements crosses from one step into another)
+#return None so that the caller can raise an exception.
+def calc_new_strides(new_shape, old_shape, old_strides):
+    #Return the proper strides for new_shape, or None
+    # if the mapping crosses stepping boundaries
+
+    #Assumes that prod(old_shape) ==prod(new_shape), len(old_shape) > 1 and
+    # len(new_shape) > 0
+    steps = []
+    last_step = 1
+    oldI = 0
+    new_strides = []
+    if old_strides[0] < old_strides[-1]:
+        for i in range(len(old_shape)):
+            steps.append(old_strides[i] / last_step)
+            last_step *= old_shape[i]
+        cur_step = steps[0]
+        n_new_elems_used = 1
+        n_old_elems_to_use = old_shape[0]
+        for s in new_shape:
+            new_strides.append(cur_step * n_new_elems_used)
+            n_new_elems_used *= s
+            while n_new_elems_used > n_old_elems_to_use:
+                oldI += 1
+                if steps[oldI] != steps[oldI - 1]:
+                    return None
+                n_old_elems_to_use *= old_shape[oldI]
+            if n_new_elems_used == n_old_elems_to_use:
+                oldI += 1
+                if oldI >= len(old_shape):
+                    break
+                cur_step = steps[oldI]
+                n_old_elems_to_use *= old_shape[oldI]
+    else:
+        for i in range(len(old_shape) - 1, -1, -1):
+            steps.insert(0, old_strides[i] / last_step)
+            last_step *= old_shape[i]
+        cur_step = steps[-1]
+        n_new_elems_used = 1
+        oldI = -1
+        n_old_elems_to_use = old_shape[-1]
+        for s in new_shape[::-1]:
+            new_strides.insert(0, cur_step * n_new_elems_used)
+            n_new_elems_used *= s
+            while n_new_elems_used > n_old_elems_to_use:
+                oldI -= 1
+                if steps[oldI] != steps[oldI + 1]:
+                    return None
+                n_old_elems_to_use *= old_shape[oldI]
+            if n_new_elems_used == n_old_elems_to_use:
+                oldI -= 1
+                if oldI < -len(old_shape):
+                    break
+                cur_step = steps[oldI]
+                n_old_elems_to_use *= old_shape[oldI]
+    return new_strides
 
 # Iterators for arrays
 # --------------------
@@ -444,6 +545,7 @@
                 return False
             i = i.next(shapelen)
         return True
+
     def descr_all(self, space):
         return space.wrap(self._all())
 
@@ -459,6 +561,7 @@
                 return True
             i = i.next(shapelen)
         return False
+
     def descr_any(self, space):
         return space.wrap(self._any())
 
@@ -483,6 +586,12 @@
     def descr_get_shape(self, space):
         return space.newtuple([space.wrap(i) for i in self.shape])
 
+    def descr_set_shape(self, space, w_iterable):
+        concrete = self.get_concrete()
+        new_shape = get_shape_from_iterable(space, 
+                            concrete.find_size(), w_iterable)
+        concrete.setshape(space, new_shape)
+
     def descr_get_size(self, space):
         return space.wrap(self.find_size())
 
@@ -730,10 +839,44 @@
             strides += self.strides[s:]
             backstrides += self.backstrides[s:]
         new_sig = signature.Signature.find_sig([
-            NDimSlice.signature, self.signature,
+            W_NDimSlice.signature, self.signature,
         ])
-        return NDimSlice(self, new_sig, start, strides[:], backstrides[:],
-                         shape[:])
+        return W_NDimSlice(self, new_sig, start, strides[:], backstrides[:],
+                           shape[:])
+
+    def descr_reshape(self, space, w_args):
+        """reshape(...)
+    a.reshape(shape)
+    
+    Returns an array containing the same data with a new shape.
+    
+    Refer to `%s.reshape` for full documentation.
+    
+    See Also
+    --------
+    numpy.reshape : equivalent function
+""" % 'numpypy'
+        concrete = self.get_concrete()
+        new_shape = get_shape_from_iterable(space, 
+                                            concrete.find_size(), w_args)
+        #Since we got to here, prod(new_shape) == self.size
+        new_strides = calc_new_strides(new_shape, 
+                                       concrete.shape, concrete.strides)
+        if new_strides:
+            #We can create a view, strides somehow match up.
+            new_sig = signature.Signature.find_sig([
+                W_NDimSlice.signature, self.signature, ])
+            ndims = len(new_shape)
+            new_backstrides = [0] * ndims
+            for nd in range(ndims):
+                new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
+            arr = W_NDimSlice(self, new_sig, self.start, new_strides,
+                              new_backstrides, new_shape)
+        else:
+            #Create copy with contiguous data
+            arr = concrete.copy()
+            arr.setshape(space, new_shape)
+        return arr
 
     def descr_mean(self, space):
         return space.div(self.descr_sum(space), space.wrap(self.find_size()))
@@ -751,7 +894,7 @@
         if len(concrete.shape) < 2:
             return space.wrap(self)
         new_sig = signature.Signature.find_sig([
-            NDimSlice.signature, self.signature
+            W_NDimSlice.signature, self.signature
         ])
         strides = []
         backstrides = []
@@ -760,8 +903,8 @@
             strides.append(concrete.strides[i])
             backstrides.append(concrete.backstrides[i])
             shape.append(concrete.shape[i])
-        return space.wrap(NDimSlice(concrete, new_sig, self.start, strides[:],
-                           backstrides[:], shape[:]))
+        return space.wrap(W_NDimSlice(concrete, new_sig, self.start, strides[:],
+                                      backstrides[:], shape[:]))
 
     def descr_get_flatiter(self, space):
         return space.wrap(W_FlatIterator(self))
@@ -830,6 +973,11 @@
     def debug_repr(self):
         return 'Scalar'
 
+    def setshape(self, space, new_shape):
+        # In order to get here, we already checked that prod(new_shape)==1,
+        # so in order to have a consistent API, let it go through.
+        pass
+
 class VirtualArray(BaseArray):
     """
     Class for representing virtual arrays, such as binary ops or ufuncs
@@ -1022,13 +1170,46 @@
             return space.wrap(self.shape[0])
         return space.wrap(1)
 
+    def setshape(self, space, new_shape):
+        if len(self.shape) < 1:
+            return
+        elif len(self.shape) < 2:
+            #TODO: this code could be refactored into calc_strides
+            #but then calc_strides would have to accept a stepping factor
+            strides = []
+            backstrides = []
+            s = self.strides[0]
+            if self.order == 'C':
+                new_shape.reverse()
+            for sh in new_shape:
+                strides.append(s)
+                backstrides.append(s * (sh - 1))
+                s *= sh
+            if self.order == 'C':
+                strides.reverse()
+                backstrides.reverse()
+                new_shape.reverse()
+            self.strides = strides[:]
+            self.backstrides = backstrides[:]
+            self.shape = new_shape[:]
+            return
+        new_strides = calc_new_strides(new_shape, self.shape, self.strides)
+        if new_strides is None:
+            raise OperationError(space.w_AttributeError, space.wrap(
+                          "incompatible shape for a non-contiguous array"))
+        new_backstrides = [0] * len(new_shape)
+        for nd in range(len(new_shape)):
+            new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
+        self.strides = new_strides[:]
+        self.backstrides = new_backstrides[:]
+        self.shape = new_shape[:]
 
-class NDimSlice(ViewArray):
+class W_NDimSlice(ViewArray):
     signature = signature.BaseSignature()
 
     def __init__(self, parent, signature, start, strides, backstrides,
                  shape):
-        if isinstance(parent, NDimSlice):
+        if isinstance(parent, W_NDimSlice):
             parent = parent.parent
         ViewArray.__init__(self, parent, signature, strides, backstrides, shape)
         self.start = start
@@ -1077,9 +1258,11 @@
     def copy(self):
         array = W_NDimArray(self.size, self.shape[:], self.find_dtype())
         iter = self.start_iter()
+        a_iter = array.start_iter()
         while not iter.done():
-            array.setitem(iter.offset, self.getitem(iter.offset))
+            array.setitem(a_iter.offset, self.getitem(iter.offset))
             iter = iter.next(len(self.shape))
+            a_iter = a_iter.next(len(array.shape))
         return array
 
 class W_NDimArray(BaseArray):
@@ -1137,6 +1320,10 @@
             return ArrayIterator(self.size)
         raise NotImplementedError  # use ViewIterator simply, test it
 
+    def setshape(self, space, new_shape):
+        self.shape = new_shape
+        self.calc_strides(new_shape)
+
     def debug_repr(self):
         return 'Array'
 
@@ -1261,7 +1448,8 @@
     __debug_repr__ = interp2app(BaseArray.descr_debug_repr),
 
     dtype = GetSetProperty(BaseArray.descr_get_dtype),
-    shape = GetSetProperty(BaseArray.descr_get_shape),
+    shape = GetSetProperty(BaseArray.descr_get_shape,
+                           BaseArray.descr_set_shape),
     size = GetSetProperty(BaseArray.descr_get_size),
 
     T = GetSetProperty(BaseArray.descr_get_transpose),
@@ -1279,6 +1467,7 @@
     dot = interp2app(BaseArray.descr_dot),
 
     copy = interp2app(BaseArray.descr_copy),
+    reshape = interp2app(BaseArray.descr_reshape),
 )
 
 
diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py
--- a/pypy/module/micronumpy/test/test_dtypes.py
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -241,6 +241,13 @@
         assert numpy.dtype(numpy.int64).type is numpy.int64
         assert numpy.int64(3) == 3
 
+    def test_float32(self):
+        import numpypy as numpy
+
+        assert numpy.float32.mro() == [numpy.float32, numpy.floating, numpy.inexact, numpy.number, numpy.generic, object]
+
+        assert numpy.float32(12) == numpy.float64(12)
+
     def test_float64(self):
         import numpypy as numpy
 
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -158,6 +158,13 @@
         assert shape_agreement(self.space,
                 [5, 2], [4, 3, 5, 2]) == [4, 3, 5, 2]
 
+    def test_calc_new_strides(self):
+        from pypy.module.micronumpy.interp_numarray import calc_new_strides
+        assert calc_new_strides([2, 4], [4, 2], [4, 2]) == [8, 2]
+        assert calc_new_strides([2, 4, 3], [8, 3], [1, 16]) == [1, 2, 16]
+        assert calc_new_strides([2, 3, 4], [8, 3], [1, 16]) is None
+        assert calc_new_strides([24], [2, 4, 3], [48, 6, 1]) is None
+        assert calc_new_strides([24], [2, 4, 3], [24, 6, 2]) == [2]
 
 class AppTestNumArray(BaseNumpyAppTest):
     def test_ndarray(self):
@@ -216,8 +223,8 @@
         assert a[2] == 4
 
     def test_copy(self):
-        from numpypy import array
-        a = array(range(5))
+        from numpypy import arange, array
+        a = arange(5)
         b = a.copy()
         for i in xrange(5):
             assert b[i] == a[i]
@@ -227,6 +234,11 @@
         a = array(1)
         assert a.copy() == a
 
+        a = arange(8)
+        b = a[::2]
+        c = b.copy()
+        assert (c == b).all()
+
     def test_iterator_init(self):
         from numpypy import array
         a = array(range(5))
@@ -339,6 +351,76 @@
         c = a[:3]
         assert c.shape == (3,)
 
+    def test_set_shape(self):
+        from numpypy import array, zeros
+        a = array([])
+        a.shape = []
+        a = array(range(12))
+        a.shape = (3, 4)
+        assert (a == [range(4), range(4, 8), range(8, 12)]).all()
+        a.shape = (3, 2, 2)
+        assert a[1, 1, 1] == 7
+        a.shape = (3, -1, 2)
+        assert a.shape == (3, 2, 2)
+        a.shape = 12
+        assert a.shape == (12, )
+        exc = raises(ValueError, "a.shape = 10")
+        assert str(exc.value) == "total size of new array must be unchanged"
+        a = array(3)
+        a.shape = ()
+        #numpy allows this
+        a.shape = (1,)
+
+    def test_reshape(self):
+        from numpypy import array, zeros
+        a = array(range(12))
+        exc = raises(ValueError, "b = a.reshape((3, 10))")
+        assert str(exc.value) == "total size of new array must be unchanged"
+        b = a.reshape((3, 4))
+        assert b.shape == (3, 4)
+        assert (b == [range(4), range(4, 8), range(8, 12)]).all()
+        b[:, 0] = 1000
+        assert (a == [1000, 1, 2, 3, 1000, 5, 6, 7, 1000, 9, 10, 11]).all()
+        a = zeros((4, 2, 3))
+        a.shape = (12, 2)
+
+    def test_slice_reshape(self):
+        from numpypy import zeros, arange
+        a = zeros((4, 2, 3))
+        b = a[::2, :, :]
+        b.shape = (2, 6)
+        exc = raises(AttributeError, "b.shape = 12")
+        assert str(exc.value) == \
+                           "incompatible shape for a non-contiguous array"
+        b = a[::2, :, :].reshape((2, 6))
+        assert b.shape == (2, 6)
+        b = arange(20)[1:17:2]
+        b.shape = (4, 2)
+        assert (b == [[1, 3], [5, 7], [9, 11], [13, 15]]).all()
+        c = b.reshape((2, 4))
+        assert (c == [[1, 3, 5, 7], [9, 11, 13, 15]]).all()
+
+        z = arange(96).reshape((12, -1))
+        assert z.shape == (12, 8)
+        y = z.reshape((4, 3, 8))
+        v = y[:, ::2, :]
+        w = y.reshape(96)
+        u = v.reshape(64)
+        assert y[1, 2, 1] == z[5, 1]
+        y[1, 2, 1] = 1000
+        #z, y, w, v are views of eachother
+        assert z[5, 1] == 1000
+        assert v[1, 1, 1] == 1000
+        assert w[41] == 1000
+        #u is not a view, it is a copy!
+        assert u[25] == 41
+
+    def test_reshape_varargs(self):
+        skip("How do I do varargs in rpython? reshape should accept a"
+             " variable number of arguments")
+        z = arange(96).reshape(12, -1)
+        y = z.reshape(4, 3, 8)
+
     def test_add(self):
         from numpypy import array
         a = array(range(5))
@@ -1155,3 +1237,14 @@
         a = arange(0, 0.8, 0.1)
         assert len(a) == 8
         assert arange(False, True, True).dtype is dtype(int)
+
+
+class AppTestRanges(BaseNumpyAppTest):
+    def test_app_reshape(self):
+        from numpypy import arange, array, dtype, reshape
+        a = arange(12)
+        b = reshape(a, (3, 4))
+        assert b.shape == (3, 4)
+        a = range(12)
+        b = reshape(a, (3, 4))
+        assert b.shape == (3, 4)
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
@@ -8,13 +8,12 @@
 from pypy.jit.metainterp import pyjitpl
 from pypy.jit.metainterp.test.support import LLJitMixin
 from pypy.jit.metainterp.warmspot import reset_stats
-from pypy.module.micronumpy import interp_boxes, interp_ufuncs, signature
-from pypy.module.micronumpy.compile import (numpy_compile, FakeSpace,
-    FloatObject, IntObject, BoolObject, Parser, InterpreterState)
-from pypy.module.micronumpy.interp_numarray import (W_NDimArray, NDimSlice,
+from pypy.module.micronumpy import interp_boxes
+from pypy.module.micronumpy.compile import (FakeSpace,
+    IntObject, Parser, InterpreterState)
+from pypy.module.micronumpy.interp_numarray import (W_NDimArray,
      BaseArray)
 from pypy.rlib.nonconst import NonConstant
-from pypy.rpython.annlowlevel import llstr, hlstr
 
 
 class TestNumpyJIt(LLJitMixin):
@@ -186,7 +185,8 @@
         # sure it was optimized correctly.
         # XXX the comment above is wrong now.  We need preferrably a way to
         # count the two loops separately
-        self.check_resops({'setinteriorfield_raw': 4, 'guard_nonnull': 1, 'getfield_gc': 41,
+        py.test.skip("counting exact number of classes is nonsense")
+        self.check_resops({'setarrayitem_raw': 4, 'guard_nonnull': 1, 'getfield_gc': 35,
                            'guard_class': 22, 'int_add': 8, 'float_mul': 2,
                            'guard_isnull': 2, 'jump': 4, 'int_ge': 4,
                            'getinteriorfield_raw': 4, 'float_add': 2, 'guard_false': 4,
diff --git a/pypy/rlib/_rsocket_rffi.py b/pypy/rlib/_rsocket_rffi.py
--- a/pypy/rlib/_rsocket_rffi.py
+++ b/pypy/rlib/_rsocket_rffi.py
@@ -418,7 +418,7 @@
 if _MSVC:
     def invalid_socket(fd):
         return fd == INVALID_SOCKET
-    INVALID_SOCKET = intmask(cConfig.INVALID_SOCKET)
+    INVALID_SOCKET = r_uint(cConfig.INVALID_SOCKET)
 else:
     def invalid_socket(fd):
         return fd < 0
diff --git a/pypy/rlib/rsocket.py b/pypy/rlib/rsocket.py
--- a/pypy/rlib/rsocket.py
+++ b/pypy/rlib/rsocket.py
@@ -20,6 +20,7 @@
 from pypy.rlib.rarithmetic import intmask, r_uint
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rpython.lltypesystem.rffi import sizeof, offsetof
+INVALID_SOCKET = _c.INVALID_SOCKET
 
 def mallocbuf(buffersize):
     return lltype.malloc(rffi.CCHARP.TO, buffersize, flavor='raw')


More information about the pypy-commit mailing list