[pypy-commit] pypy numpypy-argminmax: merge default into branch

mattip noreply at buildbot.pypy.org
Wed Jul 4 23:05:20 CEST 2012


Author: mattip <matti.picus at gmail.com>
Branch: numpypy-argminmax
Changeset: r55923:5e348c42ac82
Date: 2012-07-05 00:01 +0300
http://bitbucket.org/pypy/pypy/changeset/5e348c42ac82/

Log:	merge default into branch

diff --git a/lib_pypy/disassembler.py b/lib_pypy/disassembler.py
--- a/lib_pypy/disassembler.py
+++ b/lib_pypy/disassembler.py
@@ -24,6 +24,11 @@
         self.lineno = lineno
         self.line_starts_here = False
 
+    def __str__(self):
+        if self.arg is None:
+            return "%s" % (self.__class__.__name__,)
+        return "%s (%s)" % (self.__class__.__name__, self.arg)
+
     def __repr__(self):
         if self.arg is None:
             return "<%s at %d>" % (self.__class__.__name__, self.pos)
diff --git a/pypy/annotation/annrpython.py b/pypy/annotation/annrpython.py
--- a/pypy/annotation/annrpython.py
+++ b/pypy/annotation/annrpython.py
@@ -133,44 +133,6 @@
         self.build_graph_types(graph, inputcells, complete_now=False)
         self.complete_helpers(policy)
         return graph
-    
-    def annotate_helper_method(self, _class, attr, args_s, policy=None):
-        """ Warning! this method is meant to be used between
-        annotation and rtyping
-        """
-        if policy is None:
-            from pypy.annotation.policy import AnnotatorPolicy
-            policy = AnnotatorPolicy()
-        
-        assert attr != '__class__'
-        classdef = self.bookkeeper.getuniqueclassdef(_class)
-        attrdef = classdef.find_attribute(attr)
-        s_result = attrdef.getvalue()
-        classdef.add_source_for_attribute(attr, classdef.classdesc)
-        self.bookkeeper
-        assert isinstance(s_result, annmodel.SomePBC)
-        olddesc = s_result.any_description()
-        desc = olddesc.bind_self(classdef)
-        args = self.bookkeeper.build_args("simple_call", args_s[:])
-        desc.consider_call_site(self.bookkeeper, desc.getcallfamily(), [desc],
-            args, annmodel.s_ImpossibleValue, None)
-        result = []
-        def schedule(graph, inputcells):
-            result.append((graph, inputcells))
-            return annmodel.s_ImpossibleValue
-
-        prevpolicy = self.policy
-        self.policy = policy
-        self.bookkeeper.enter(None)
-        try:
-            desc.pycall(schedule, args, annmodel.s_ImpossibleValue)
-        finally:
-            self.bookkeeper.leave()
-            self.policy = prevpolicy
-        [(graph, inputcells)] = result
-        self.build_graph_types(graph, inputcells, complete_now=False)
-        self.complete_helpers(policy)
-        return graph
 
     def complete_helpers(self, policy):
         saved = self.policy, self.added_blocks
diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -514,9 +514,9 @@
                     continue
                 self.add_source_attribute(name, value, mixin=True)
 
-    def add_sources_for_class(self, cls, mixin=False):
+    def add_sources_for_class(self, cls):
         for name, value in cls.__dict__.items():
-            self.add_source_attribute(name, value, mixin)
+            self.add_source_attribute(name, value)
 
     def getallclassdefs(self):
         return self._classdefs.values()
diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py
--- a/pypy/annotation/test/test_annrpython.py
+++ b/pypy/annotation/test/test_annrpython.py
@@ -2747,20 +2747,6 @@
         s = a.build_types(f, [])
         assert s.knowntype == int
 
-    def test_helper_method_annotator(self):
-        def fun():
-            return 21
-
-        class A(object):
-            def helper(self):
-                return 42
-
-        a = self.RPythonAnnotator()
-        a.build_types(fun, [])
-        a.annotate_helper_method(A, "helper", [])
-        assert a.bookkeeper.getdesc(A.helper).getuniquegraph()
-        assert a.bookkeeper.getdesc(A().helper).getuniquegraph()
-
     def test_chr_out_of_bounds(self):
         def g(n, max):
             if n < max:
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
@@ -71,7 +71,7 @@
         c = Config(descr)
         for path in c.getpaths(include_groups=True):
             fn = prefix + "." + path + ".txt"
-            yield check_file_exists, fn
+            yield fn, check_file_exists, fn
 
 def test__ffi_opt():
     config = get_pypy_config(translating=True)
diff --git a/pypy/doc/config/objspace.usemodules.cppyy.txt b/pypy/doc/config/objspace.usemodules.cppyy.txt
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/objspace.usemodules.cppyy.txt
@@ -0,0 +1,1 @@
+Use the 'cppyy' module
diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
--- a/pypy/doc/cppyy.rst
+++ b/pypy/doc/cppyy.rst
@@ -87,14 +87,19 @@
     $ cd pypy
     $ hg up reflex-support         # optional
     $ cd pypy/translator/goal
+    
+    # This example shows python, but using pypy-c is faster and uses less memory
     $ python translate.py -O jit --gcrootfinder=shadowstack targetpypystandalone.py --withmod-cppyy
 
 This will build a ``pypy-c`` that includes the cppyy module, and through that,
 Reflex support.
 Of course, if you already have a pre-built version of the ``pypy`` interpreter,
 you can use that for the translation rather than ``python``.
+If not, you may want `to obtain a binary distribution`_ to speed up the
+translation step.
 
 .. _`PyPy sources`: https://bitbucket.org/pypy/pypy/overview
+.. _`to obtain a binary distribution`: http://doc.pypy.org/en/latest/getting-started.html#download-a-pre-built-pypy
 
 
 Basic example
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
@@ -11,7 +11,8 @@
 .. branch: reflex-support
 Provides cppyy module (disabled by default) for access to C++ through Reflex.
 See doc/cppyy.rst for full details and functionality.
-
+.. branch: nupypy-axis-arg-check
+Check that axis arg is valid in _numpypy
 
 .. "uninteresting" branches that we should just ignore for the whatsnew:
 .. branch: slightly-shorter-c
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -496,7 +496,12 @@
 
     # apply kw_spec
     for name, spec in kw_spec.items():
-        unwrap_spec[argnames.index(name)] = spec
+        try:
+            unwrap_spec[argnames.index(name)] = spec
+        except ValueError:
+            raise ValueError("unwrap_spec() got a keyword %r but it is not "
+                             "the name of an argument of the following "
+                             "function" % (name,))
 
     return unwrap_spec
 
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -227,20 +227,29 @@
             # length
             self.setlen(0)
 
-        def setlen(self, size):
+        def setlen(self, size, zero=False, overallocate=True):
             if size > 0:
                 if size > self.allocated or size < self.allocated / 2:
-                    if size < 9:
-                        some = 3
+                    if overallocate:
+                        if size < 9:
+                            some = 3
+                        else:
+                            some = 6
+                        some += size >> 3
                     else:
-                        some = 6
-                    some += size >> 3
+                        some = 0
                     self.allocated = size + some
-                    new_buffer = lltype.malloc(mytype.arraytype,
-                                               self.allocated, flavor='raw',
-                                               add_memory_pressure=True)
-                    for i in range(min(size, self.len)):
-                        new_buffer[i] = self.buffer[i]
+                    if zero:
+                        new_buffer = lltype.malloc(mytype.arraytype,
+                                                   self.allocated, flavor='raw',
+                                                   add_memory_pressure=True,
+                                                   zero=True)
+                    else:
+                        new_buffer = lltype.malloc(mytype.arraytype,
+                                                   self.allocated, flavor='raw',
+                                                   add_memory_pressure=True)
+                        for i in range(min(size, self.len)):
+                            new_buffer[i] = self.buffer[i]
                 else:
                     self.len = size
                     return
@@ -346,7 +355,7 @@
     def getitem__Array_Slice(space, self, w_slice):
         start, stop, step, size = space.decode_index4(w_slice, self.len)
         w_a = mytype.w_class(self.space)
-        w_a.setlen(size)
+        w_a.setlen(size, overallocate=False)
         assert step != 0
         j = 0
         for i in range(start, stop, step):
@@ -368,26 +377,18 @@
     def setitem__Array_Slice_Array(space, self, w_idx, w_item):
         start, stop, step, size = self.space.decode_index4(w_idx, self.len)
         assert step != 0
-        if w_item.len != size:
+        if w_item.len != size or self is w_item:
+            # XXX this is a giant slow hack
             w_lst = array_tolist__Array(space, self)
             w_item = space.call_method(w_item, 'tolist')
             space.setitem(w_lst, w_idx, w_item)
             self.setlen(0)
             self.fromsequence(w_lst)
         else:
-            if self is w_item:
-                with lltype.scoped_alloc(mytype.arraytype, self.allocated) as new_buffer:
-                    for i in range(self.len):
-                        new_buffer[i] = w_item.buffer[i]
-                    j = 0
-                    for i in range(start, stop, step):
-                        self.buffer[i] = new_buffer[j]
-                        j += 1
-            else:
-                j = 0
-                for i in range(start, stop, step):
-                    self.buffer[i] = w_item.buffer[j]
-                    j += 1
+            j = 0
+            for i in range(start, stop, step):
+                self.buffer[i] = w_item.buffer[j]
+                j += 1
 
     def setslice__Array_ANY_ANY_ANY(space, self, w_i, w_j, w_x):
         space.setitem(self, space.newslice(w_i, w_j, space.w_None), w_x)
@@ -459,6 +460,7 @@
         self.buffer[i] = val
 
     def delitem__Array_ANY(space, self, w_idx):
+        # XXX this is a giant slow hack
         w_lst = array_tolist__Array(space, self)
         space.delitem(w_lst, w_idx)
         self.setlen(0)
@@ -471,7 +473,7 @@
 
     def add__Array_Array(space, self, other):
         a = mytype.w_class(space)
-        a.setlen(self.len + other.len)
+        a.setlen(self.len + other.len, overallocate=False)
         for i in range(self.len):
             a.buffer[i] = self.buffer[i]
         for i in range(other.len):
@@ -487,46 +489,50 @@
         return self
 
     def mul__Array_ANY(space, self, w_repeat):
+        return _mul_helper(space, self, w_repeat, False)
+
+    def mul__ANY_Array(space, w_repeat, self):
+        return _mul_helper(space, self, w_repeat, False)
+
+    def inplace_mul__Array_ANY(space, self, w_repeat):
+        return _mul_helper(space, self, w_repeat, True)
+
+    def _mul_helper(space, self, w_repeat, is_inplace):
         try:
             repeat = space.getindex_w(w_repeat, space.w_OverflowError)
         except OperationError, e:
             if e.match(space, space.w_TypeError):
                 raise FailedToImplement
             raise
-        a = mytype.w_class(space)
         repeat = max(repeat, 0)
         try:
             newlen = ovfcheck(self.len * repeat)
         except OverflowError:
             raise MemoryError
-        a.setlen(newlen)
-        for r in range(repeat):
-            for i in range(self.len):
-                a.buffer[r * self.len + i] = self.buffer[i]
+        oldlen = self.len
+        if is_inplace:
+            a = self
+            start = 1
+        else:
+            a = mytype.w_class(space)
+            start = 0
+        # <a performance hack>
+        if oldlen == 1:
+            if self.buffer[0] == rffi.cast(mytype.itemtype, 0):
+                a.setlen(newlen, zero=True, overallocate=False)
+                return a
+            a.setlen(newlen, overallocate=False)
+            item = self.buffer[0]
+            for r in range(start, repeat):
+                a.buffer[r] = item
+            return a
+        # </a performance hack>
+        a.setlen(newlen, overallocate=False)
+        for r in range(start, repeat):
+            for i in range(oldlen):
+                a.buffer[r * oldlen + i] = self.buffer[i]
         return a
 
-    def mul__ANY_Array(space, w_repeat, self):
-        return mul__Array_ANY(space, self, w_repeat)
-
-    def inplace_mul__Array_ANY(space, self, w_repeat):
-        try:
-            repeat = space.getindex_w(w_repeat, space.w_OverflowError)
-        except OperationError, e:
-            if e.match(space, space.w_TypeError):
-                raise FailedToImplement
-            raise
-        oldlen = self.len
-        repeat = max(repeat, 0)
-        try:
-            newlen = ovfcheck(self.len * repeat)
-        except OverflowError:
-            raise MemoryError
-        self.setlen(newlen)
-        for r in range(1, repeat):
-            for i in range(oldlen):
-                self.buffer[r * oldlen + i] = self.buffer[i]
-        return self
-
     # Convertions
 
     def array_tolist__Array(space, self):
@@ -602,6 +608,7 @@
     # Compare methods
     @specialize.arg(3)
     def _cmp_impl(space, self, other, space_fn):
+        # XXX this is a giant slow hack
         w_lst1 = array_tolist__Array(space, self)
         w_lst2 = space.call_method(other, 'tolist')
         return space_fn(w_lst1, w_lst2)
@@ -648,7 +655,7 @@
 
     def array_copy__Array(space, self):
         w_a = mytype.w_class(self.space)
-        w_a.setlen(self.len)
+        w_a.setlen(self.len, overallocate=False)
         rffi.c_memcpy(
             rffi.cast(rffi.VOIDP, w_a.buffer),
             rffi.cast(rffi.VOIDP, self.buffer),
diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -890,6 +890,46 @@
         a[::-1] = a
         assert a == self.array('b', [3, 2, 1, 0])
 
+    def test_array_multiply(self):
+        a = self.array('b', [0])
+        b = a * 13
+        assert b[12] == 0
+        b = 13 * a
+        assert b[12] == 0
+        a *= 13
+        assert a[12] == 0
+        a = self.array('b', [1])
+        b = a * 13
+        assert b[12] == 1
+        b = 13 * a
+        assert b[12] == 1
+        a *= 13
+        assert a[12] == 1
+        a = self.array('i', [0])
+        b = a * 13
+        assert b[12] == 0
+        b = 13 * a
+        assert b[12] == 0
+        a *= 13
+        assert a[12] == 0
+        a = self.array('i', [1])
+        b = a * 13
+        assert b[12] == 1
+        b = 13 * a
+        assert b[12] == 1
+        a *= 13
+        assert a[12] == 1
+        a = self.array('i', [0, 0])
+        b = a * 13
+        assert len(b) == 26
+        assert b[22] == 0
+        b = 13 * a
+        assert len(b) == 26
+        assert b[22] == 0
+        a *= 13
+        assert a[22] == 0
+        assert len(a) == 26        
+
 
 class AppTestArrayBuiltinShortcut(AppTestArray):
     OPTIONS = {'objspace.std.builtinshortcut': True}
diff --git a/pypy/module/cppyy/test/conftest.py b/pypy/module/cppyy/test/conftest.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/conftest.py
@@ -0,0 +1,5 @@
+import py
+
+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/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py
--- a/pypy/module/cppyy/test/test_cppyy.py
+++ b/pypy/module/cppyy/test/test_cppyy.py
@@ -145,7 +145,7 @@
         e1 = None
         gc.collect()
         assert t.get_overload("getCount").call(None) == 1
-	e2.destruct()
+        e2.destruct()
         assert t.get_overload("getCount").call(None) == 0
         e2 = None
         gc.collect()
diff --git a/pypy/module/cppyy/test/test_operators.py b/pypy/module/cppyy/test/test_operators.py
--- a/pypy/module/cppyy/test/test_operators.py
+++ b/pypy/module/cppyy/test/test_operators.py
@@ -133,7 +133,7 @@
 
         o = gbl.operator_unsigned_long();
         o.m_ulong = sys.maxint + 128
-	assert o.m_ulong == sys.maxint + 128
+        assert o.m_ulong == sys.maxint + 128
         assert long(o)   == sys.maxint + 128
 
         o = gbl.operator_float(); o.m_float = 3.14
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
@@ -163,6 +163,7 @@
         'sum': 'app_numpy.sum',
         'min': 'app_numpy.min',
         'identity': 'app_numpy.identity',
+        'eye': 'app_numpy.eye',
         'max': 'app_numpy.max',
         'arange': 'app_numpy.arange',
     }
diff --git a/pypy/module/micronumpy/app_numpy.py b/pypy/module/micronumpy/app_numpy.py
--- a/pypy/module/micronumpy/app_numpy.py
+++ b/pypy/module/micronumpy/app_numpy.py
@@ -16,6 +16,26 @@
         a[i][i] = 1
     return a
 
+def eye(n, m=None, k=0, dtype=None):
+    if m is None:
+        m = n
+    a = _numpypy.zeros((n, m), dtype=dtype)
+    ni = 0
+    mi = 0
+
+    if k < 0:
+        p = n + k
+        ni = -k
+    else:
+        p = n - k
+        mi = k
+
+    while ni < n and mi < m:
+        a[ni][mi] = 1
+        ni += 1
+        mi += 1
+    return a
+
 def sum(a,axis=None, out=None):
     '''sum(a, axis=None)
     Sum of array elements over a given axis.
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
@@ -1155,6 +1155,38 @@
         assert d.shape == (3, 3)
         assert d.dtype == dtype('int32')
         assert (d == [[1, 0, 0], [0, 1, 0], [0, 0, 1]]).all()
+   
+    def test_eye(self):
+        from _numpypy import eye, array
+        from _numpypy import int32, float64, dtype
+        a = eye(0)
+        assert len(a) == 0
+        assert a.dtype == dtype('float64')
+        assert a.shape == (0, 0)
+        b = eye(1, dtype=int32)
+        assert len(b) == 1
+        assert b[0][0] == 1
+        assert b.shape == (1, 1)
+        assert b.dtype == dtype('int32')
+        c = eye(2)
+        assert c.shape == (2, 2)
+        assert (c == [[1, 0], [0, 1]]).all()
+        d = eye(3, dtype='int32')
+        assert d.shape == (3, 3)
+        assert d.dtype == dtype('int32')
+        assert (d == [[1, 0, 0], [0, 1, 0], [0, 0, 1]]).all()
+        e = eye(3, 4)
+        assert e.shape == (3, 4)
+        assert (e == [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]]).all()
+        f = eye(2, 4, k=3)
+        assert f.shape == (2, 4)
+        assert (f == [[0, 0, 0, 1], [0, 0, 0, 0]]).all()
+        g = eye(3, 4, k=-1)
+        assert g.shape == (3, 4)
+        assert (g == [[0, 0, 0, 0], [1, 0, 0, 0], [0, 1, 0, 0]]).all()
+
+
+
 
     def test_prod(self):
         from _numpypy import array
diff --git a/pypy/module/select/interp_kqueue.py b/pypy/module/select/interp_kqueue.py
--- a/pypy/module/select/interp_kqueue.py
+++ b/pypy/module/select/interp_kqueue.py
@@ -7,6 +7,7 @@
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.tool import rffi_platform
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
+import sys
 
 
 eci = ExternalCompilationInfo(
@@ -20,14 +21,26 @@
     _compilation_info_ = eci
 
 
-CConfig.kevent = rffi_platform.Struct("struct kevent", [
-    ("ident", rffi.UINTPTR_T),
-    ("filter", rffi.SHORT),
-    ("flags", rffi.USHORT),
-    ("fflags", rffi.UINT),
-    ("data", rffi.INTPTR_T),
-    ("udata", rffi.VOIDP),
-])
+if "openbsd" in sys.platform:
+    IDENT_UINT = True
+    CConfig.kevent = rffi_platform.Struct("struct kevent", [
+        ("ident", rffi.UINT),
+        ("filter", rffi.SHORT),
+        ("flags", rffi.USHORT),
+        ("fflags", rffi.UINT),
+        ("data", rffi.INT),
+        ("udata", rffi.VOIDP),
+    ])
+else:
+    IDENT_UINT = False
+    CConfig.kevent = rffi_platform.Struct("struct kevent", [
+        ("ident", rffi.UINTPTR_T),
+        ("filter", rffi.SHORT),
+        ("flags", rffi.USHORT),
+        ("fflags", rffi.UINT),
+        ("data", rffi.INTPTR_T),
+        ("udata", rffi.VOIDP),
+    ])
 
 
 CConfig.timespec = rffi_platform.Struct("struct timespec", [
@@ -243,16 +256,24 @@
         self.event.c_udata = rffi.cast(rffi.VOIDP, udata)
 
     def _compare_all_fields(self, other, op):
-        l_ident = self.event.c_ident
-        r_ident = other.event.c_ident
+        if IDENT_UINT:
+            l_ident = rffi.cast(lltype.Unsigned, self.event.c_ident)
+            r_ident = rffi.cast(lltype.Unsigned, other.event.c_ident)
+        else:
+            l_ident = self.event.c_ident
+            r_ident = other.event.c_ident
         l_filter = rffi.cast(lltype.Signed, self.event.c_filter)
         r_filter = rffi.cast(lltype.Signed, other.event.c_filter)
         l_flags = rffi.cast(lltype.Unsigned, self.event.c_flags)
         r_flags = rffi.cast(lltype.Unsigned, other.event.c_flags)
         l_fflags = rffi.cast(lltype.Unsigned, self.event.c_fflags)
         r_fflags = rffi.cast(lltype.Unsigned, other.event.c_fflags)
-        l_data = self.event.c_data
-        r_data = other.event.c_data
+        if IDENT_UINT:
+            l_data = rffi.cast(lltype.Signed, self.event.c_data)
+            r_data = rffi.cast(lltype.Signed, other.event.c_data)
+        else:
+            l_data = self.event.c_data
+            r_data = other.event.c_data
         l_udata = rffi.cast(lltype.Unsigned, self.event.c_udata)
         r_udata = rffi.cast(lltype.Unsigned, other.event.c_udata)
 
diff --git a/pypy/rlib/parsing/parsing.py b/pypy/rlib/parsing/parsing.py
--- a/pypy/rlib/parsing/parsing.py
+++ b/pypy/rlib/parsing/parsing.py
@@ -107,14 +107,12 @@
         error = None # for the annotator
         if self.parser.is_nonterminal(symbol):
             rule = self.parser.get_rule(symbol)
-            lastexpansion = len(rule.expansions) - 1
             subsymbol = None
             error = None
             for expansion in rule.expansions:
                 curr = i
                 children = []
-                for j in range(len(expansion)):
-                    subsymbol = expansion[j]
+                for subsymbol in expansion:
                     node, next, error2 = self.match_symbol(curr, subsymbol)
                     if node is None:
                         error = combine_errors(error, error2)
diff --git a/pypy/rlib/rerased.py b/pypy/rlib/rerased.py
--- a/pypy/rlib/rerased.py
+++ b/pypy/rlib/rerased.py
@@ -48,6 +48,9 @@
     def __repr__(self):
         return 'ErasingPairIdentity(%r)' % self.name
 
+    def __deepcopy__(self, memo):
+        return self
+
     def _getdict(self, bk):
         try:
             dict = bk._erasing_pairs_tunnel
diff --git a/pypy/rlib/test/test_rerased.py b/pypy/rlib/test/test_rerased.py
--- a/pypy/rlib/test/test_rerased.py
+++ b/pypy/rlib/test/test_rerased.py
@@ -1,5 +1,7 @@
 import py
 import sys
+import copy
+
 from pypy.rlib.rerased import *
 from pypy.annotation import model as annmodel
 from pypy.annotation.annrpython import RPythonAnnotator
@@ -59,6 +61,13 @@
     #assert is_integer(e) is False
     assert unerase_list_X(e) is l
 
+def test_deepcopy():
+    x = "hello"
+    e = eraseX(x)
+    e2 = copy.deepcopy(e)
+    assert uneraseX(e) is x
+    assert uneraseX(e2) is x
+
 def test_annotate_1():
     def f():
         return eraseX(X())
diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py
--- a/pypy/rpython/lltypesystem/rlist.py
+++ b/pypy/rpython/lltypesystem/rlist.py
@@ -170,8 +170,8 @@
 
 # adapted C code
 
- at enforceargs(None, int)
-def _ll_list_resize_really(l, newsize):
+ at enforceargs(None, int, None)
+def _ll_list_resize_really(l, newsize, overallocate):
     """
     Ensure l.items has room for at least newsize elements, and set
     l.length to newsize.  Note that l.items may change, and even if
@@ -188,13 +188,15 @@
         l.length = 0
         l.items = _ll_new_empty_item_array(typeOf(l).TO)
         return
-    else:
+    elif overallocate:
         if newsize < 9:
             some = 3
         else:
             some = 6
         some += newsize >> 3
         new_allocated = newsize + some
+    else:
+        new_allocated = newsize
     # new_allocated is a bit more than newsize, enough to ensure an amortized
     # linear complexity for e.g. repeated usage of l.append().  In case
     # it overflows sys.maxint, it is guaranteed negative, and the following
@@ -214,31 +216,36 @@
 # this common case was factored out of _ll_list_resize
 # to see if inlining it gives some speed-up.
 
+ at jit.dont_look_inside
 def _ll_list_resize(l, newsize):
-    # Bypass realloc() when a previous overallocation is large enough
-    # to accommodate the newsize.  If the newsize falls lower than half
-    # the allocated size, then proceed with the realloc() to shrink the list.
-    allocated = len(l.items)
-    if allocated >= newsize and newsize >= ((allocated >> 1) - 5):
-        l.length = newsize
-    else:
-        _ll_list_resize_really(l, newsize)
+    """Called only in special cases.  Forces the allocated and actual size
+    of the list to be 'newsize'."""
+    _ll_list_resize_really(l, newsize, False)
 
 @jit.look_inside_iff(lambda l, newsize: jit.isconstant(len(l.items)) and jit.isconstant(newsize))
 @jit.oopspec("list._resize_ge(l, newsize)")
 def _ll_list_resize_ge(l, newsize):
+    """This is called with 'newsize' larger than the current length of the
+    list.  If the list storage doesn't have enough space, then really perform
+    a realloc().  In the common case where we already overallocated enough,
+    then this is a very fast operation.
+    """
     if len(l.items) >= newsize:
         l.length = newsize
     else:
-        _ll_list_resize_really(l, newsize)
+        _ll_list_resize_really(l, newsize, True)
 
 @jit.look_inside_iff(lambda l, newsize: jit.isconstant(len(l.items)) and jit.isconstant(newsize))
 @jit.oopspec("list._resize_le(l, newsize)")
 def _ll_list_resize_le(l, newsize):
+    """This is called with 'newsize' smaller than the current length of the
+    list.  If 'newsize' falls lower than half the allocated size, proceed
+    with the realloc() to shrink the list.
+    """
     if newsize >= (len(l.items) >> 1) - 5:
         l.length = newsize
     else:
-        _ll_list_resize_really(l, newsize)
+        _ll_list_resize_really(l, newsize, False)
 
 def ll_append_noresize(l, newitem):
     length = l.length
diff --git a/pypy/rpython/module/ll_os.py b/pypy/rpython/module/ll_os.py
--- a/pypy/rpython/module/ll_os.py
+++ b/pypy/rpython/module/ll_os.py
@@ -144,7 +144,7 @@
     # XXX many of these includes are not portable at all
     includes += ['dirent.h', 'sys/stat.h',
                  'sys/times.h', 'utime.h', 'sys/types.h', 'unistd.h',
-                 'signal.h', 'sys/wait.h', 'fcntl.h', 'pty.h']
+                 'signal.h', 'sys/wait.h', 'fcntl.h']
 else:
     includes += ['sys/utime.h']
 
diff --git a/pypy/rpython/normalizecalls.py b/pypy/rpython/normalizecalls.py
--- a/pypy/rpython/normalizecalls.py
+++ b/pypy/rpython/normalizecalls.py
@@ -39,7 +39,8 @@
                                                               row)
             if did_something:
                 assert not callfamily.normalized, "change in call family normalisation"
-                assert nshapes == 1, "XXX call table too complex"
+                if nshapes != 1:
+                    raise_call_table_too_complex_error(callfamily, annotator)
     while True: 
         progress = False
         for shape, table in callfamily.calltables.items():
@@ -50,6 +51,38 @@
             return   # done
         assert not callfamily.normalized, "change in call family normalisation"
 
+def raise_call_table_too_complex_error(callfamily, annotator):
+    msg = []
+    items = callfamily.calltables.items()
+    for i, (shape1, table1) in enumerate(items):
+        for shape2, table2 in items[i + 1:]:
+            if shape1 == shape2:
+                continue
+            row1 = table1[0]
+            row2 = table2[0]
+            problematic_function_graphs = set(row1.values()).union(set(row2.values()))
+            pfg = [str(graph) for graph in problematic_function_graphs]
+            pfg.sort()
+            msg.append("the following functions:")
+            msg.append("    %s" % ("\n    ".join(pfg), ))
+            msg.append("are called with inconsistent numbers of arguments")
+            if shape1[0] != shape2[0]:
+                msg.append("sometimes with %s arguments, sometimes with %s" % (shape1[0], shape2[0]))
+            else:
+                pass # XXX better message in this case
+            callers = []
+            msg.append("the callers of these functions are:")
+            for tag, (caller, callee) in annotator.translator.callgraph.iteritems():
+                if callee not in problematic_function_graphs:
+                    continue
+                if str(caller) in callers:
+                    continue
+                callers.append(str(caller))
+            callers.sort()
+            for caller in callers:
+                msg.append("    %s" % (caller, ))
+    raise TyperError("\n".join(msg))
+
 def normalize_calltable_row_signature(annotator, shape, row):
     graphs = row.values()
     assert graphs, "no graph??"
diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py
--- a/pypy/rpython/rlist.py
+++ b/pypy/rpython/rlist.py
@@ -20,8 +20,11 @@
     'll_setitem_fast': (['self', Signed, 'item'], Void),
 })
 ADTIList = ADTInterface(ADTIFixedList, {
+    # grow the length if needed, overallocating a bit
     '_ll_resize_ge':   (['self', Signed        ], Void),
+    # shrink the length, keeping it overallocated if useful
     '_ll_resize_le':   (['self', Signed        ], Void),
+    # resize to exactly the given size
     '_ll_resize':      (['self', Signed        ], Void),
 })
 
@@ -1018,6 +1021,8 @@
     ll_delitem_nonneg(dum_nocheck, lst, index)
 
 def ll_inplace_mul(l, factor):
+    if factor == 1:
+        return l
     length = l.ll_length()
     if factor < 0:
         factor = 0
@@ -1027,7 +1032,6 @@
         raise MemoryError
     res = l
     res._ll_resize(resultlen)
-    #res._ll_resize_ge(resultlen)
     j = length
     while j < resultlen:
         i = 0
diff --git a/pypy/rpython/test/test_normalizecalls.py b/pypy/rpython/test/test_normalizecalls.py
--- a/pypy/rpython/test/test_normalizecalls.py
+++ b/pypy/rpython/test/test_normalizecalls.py
@@ -2,6 +2,7 @@
 from pypy.annotation import model as annmodel
 from pypy.translator.translator import TranslationContext, graphof
 from pypy.rpython.llinterp import LLInterpreter
+from pypy.rpython.error import TyperError
 from pypy.rpython.test.test_llinterp import interpret
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.normalizecalls import TotalOrderSymbolic, MAX
@@ -158,6 +159,39 @@
         res = llinterp.eval_graph(graphof(translator, dummyfn), [2])
         assert res == -2
 
+    def test_methods_with_defaults(self):
+        class Base:
+            def fn(self):
+                raise NotImplementedError
+        class Sub1(Base):
+            def fn(self, x=1):
+                return 1 + x
+        class Sub2(Base):
+            def fn(self):
+                return -2
+        def otherfunc(x):
+            return x.fn()
+        def dummyfn(n):
+            if n == 1:
+                x = Sub1()
+                n = x.fn(2)
+            else:
+                x = Sub2()
+            return otherfunc(x) + x.fn()
+
+        excinfo = py.test.raises(TyperError, "self.rtype(dummyfn, [int], int)")
+        msg = """the following functions:
+    .+Base.fn
+    .+Sub1.fn
+    .+Sub2.fn
+are called with inconsistent numbers of arguments
+sometimes with 2 arguments, sometimes with 1
+the callers of these functions are:
+    .+otherfunc
+    .+dummyfn"""
+        import re
+        assert re.match(msg, excinfo.value.args[0])
+
 
 class PBase:
     def fn(self):
diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py
--- a/pypy/tool/jitlogparser/parser.py
+++ b/pypy/tool/jitlogparser/parser.py
@@ -5,6 +5,22 @@
 from pypy.tool.logparser import parse_log_file, extract_category
 from copy import copy
 
+def parse_code_data(arg):
+    name = None
+    lineno = 0
+    filename = None
+    bytecode_no = 0
+    bytecode_name = None
+    m = re.search('<code object ([<>\w]+)[\.,] file \'(.+?)\'[\.,] line (\d+)> #(\d+) (\w+)',
+                  arg)
+    if m is None:
+        # a non-code loop, like StrLiteralSearch or something
+        if arg:
+            bytecode_name = arg
+    else:
+        name, filename, lineno, bytecode_no, bytecode_name = m.groups()
+    return name, bytecode_name, filename, int(lineno), int(bytecode_no)
+
 class Op(object):
     bridge = None
     offset = None
@@ -132,38 +148,24 @@
     pass
 
 class TraceForOpcode(object):
-    filename = None
-    startlineno = 0
-    name = None
     code = None
-    bytecode_no = 0
-    bytecode_name = None
     is_bytecode = True
     inline_level = None
     has_dmp = False
 
-    def parse_code_data(self, arg):
-        m = re.search('<code object ([<>\w]+)[\.,] file \'(.+?)\'[\.,] line (\d+)> #(\d+) (\w+)',
-                      arg)
-        if m is None:
-            # a non-code loop, like StrLiteralSearch or something
-            if arg:
-                self.bytecode_name = arg
-        else:
-            self.name, self.filename, lineno, bytecode_no, self.bytecode_name = m.groups()
-            self.startlineno = int(lineno)
-            self.bytecode_no = int(bytecode_no)
-
-
     def __init__(self, operations, storage, loopname):
         for op in operations:
             if op.name == 'debug_merge_point':
                 self.inline_level = int(op.args[0])
-                self.parse_code_data(op.args[2][1:-1])
+                parsed = parse_code_data(op.args[2][1:-1])
+                (self.name, self.bytecode_name, self.filename,
+                 self.startlineno, self.bytecode_no) = parsed
                 break
         else:
             self.inline_level = 0
-            self.parse_code_data(loopname)
+            parsed = parse_code_data(loopname)
+            (self.name, self.bytecode_name, self.filename,
+             self.startlineno, self.bytecode_no) = parsed
         self.operations = operations
         self.storage = storage
         self.code = storage.disassemble_code(self.filename, self.startlineno,
diff --git a/pypy/tool/sourcetools.py b/pypy/tool/sourcetools.py
--- a/pypy/tool/sourcetools.py
+++ b/pypy/tool/sourcetools.py
@@ -224,6 +224,7 @@
     if func.func_dict:
         f.func_dict = {}
         f.func_dict.update(func.func_dict)
+    f.func_doc = func.func_doc
     return f
 
 def func_renamer(newname):
diff --git a/pypy/tool/test/test_sourcetools.py b/pypy/tool/test/test_sourcetools.py
--- a/pypy/tool/test/test_sourcetools.py
+++ b/pypy/tool/test/test_sourcetools.py
@@ -22,3 +22,15 @@
     assert f.func_name == "g"
     assert f.func_defaults == (5,)
     assert f.prop is int
+
+def test_func_rename_decorator():
+    def bar():
+        'doc'
+
+    bar2 = func_with_new_name(bar, 'bar2')
+    assert bar.func_doc == bar2.func_doc == 'doc'
+
+    bar.func_doc = 'new doc'
+    bar3 = func_with_new_name(bar, 'bar3')
+    assert bar3.func_doc == 'new doc'
+    assert bar2.func_doc != bar3.func_doc


More information about the pypy-commit mailing list