[pypy-commit] pypy reflex-support: hg merge default

cfbolz noreply at buildbot.pypy.org
Wed Jul 13 14:12:53 CEST 2011


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: reflex-support
Changeset: r45539:f37b832e2ed3
Date: 2011-07-13 14:08 +0200
http://bitbucket.org/pypy/pypy/changeset/f37b832e2ed3/

Log:	hg merge default

diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -925,6 +925,9 @@
                 return self.w_True
         return self.w_False
 
+    def issequence_w(self, w_obj):
+        return (self.findattr(w_obj, self.wrap("__getitem__")) is not None)
+
     def isinstance_w(self, w_obj, w_type):
         return self.is_true(self.isinstance(w_obj, w_type))
 
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -765,13 +765,58 @@
             raise NotImplementedError("cast_ptr_to_int")
 
     def rewrite_op_force_cast(self, op):
+        assert not self._is_gc(op.args[0])
+        fromll = longlong.is_longlong(op.args[0].concretetype)
+        toll   = longlong.is_longlong(op.result.concretetype)
+        if fromll and toll:
+            return
+        if fromll:
+            args = op.args
+            opname = 'truncate_longlong_to_int'
+            RESULT = lltype.Signed
+            v = varoftype(RESULT)
+            op1 = SpaceOperation(opname, args, v)
+            op2 = self.rewrite_operation(op1)
+            oplist = self.force_cast_without_longlong(op2.result, op.result)
+            if oplist:
+                return [op2] + oplist
+            #
+            # force a renaming to put the correct result in place, even though
+            # it might be slightly mistyped (e.g. Signed versus Unsigned)
+            assert op2.result is v
+            op2.result = op.result
+            return op2
+        elif toll:
+            from pypy.rpython.lltypesystem import rffi
+            size, unsigned = rffi.size_and_sign(op.args[0].concretetype)
+            if unsigned:
+                INTERMEDIATE = lltype.Unsigned
+            else:
+                INTERMEDIATE = lltype.Signed
+            v = varoftype(INTERMEDIATE)
+            oplist = self.force_cast_without_longlong(op.args[0], v)
+            if not oplist:
+                v = op.args[0]
+                oplist = []
+            if unsigned:
+                opname = 'cast_uint_to_longlong'
+            else:
+                opname = 'cast_int_to_longlong'
+            op1 = SpaceOperation(opname, [v], op.result)
+            op2 = self.rewrite_operation(op1)
+            return oplist + [op2]
+        else:
+            return self.force_cast_without_longlong(op.args[0], op.result)
+
+    def force_cast_without_longlong(self, v_arg, v_result):
         from pypy.rpython.lltypesystem.rffi import size_and_sign, sizeof
         from pypy.rlib.rarithmetic import intmask
-        assert not self._is_gc(op.args[0])
-        size2, unsigned2 = size_and_sign(op.result.concretetype)
-        if size2 >= sizeof(lltype.Signed):
+        size2, unsigned2 = size_and_sign(v_result.concretetype)
+        assert size2 <= sizeof(lltype.Signed)
+        if size2 == sizeof(lltype.Signed):
             return     # the target type is LONG or ULONG
-        size1, unsigned1 = size_and_sign(op.args[0].concretetype)
+        size1, unsigned1 = size_and_sign(v_arg.concretetype)
+        assert size1 <= sizeof(lltype.Signed)
         #
         def bounds(size, unsigned):
             if unsigned:
@@ -784,20 +829,19 @@
             return     # the target type includes the source range
         #
         result = []
-        v1 = op.args[0]
         if min2:
             c_min2 = Constant(min2, lltype.Signed)
-            v2 = Variable(); v2.concretetype = lltype.Signed
-            result.append(SpaceOperation('int_sub', [v1, c_min2], v2))
+            v2 = varoftype(lltype.Signed)
+            result.append(SpaceOperation('int_sub', [v_arg, c_min2], v2))
         else:
-            v2 = v1
+            v2 = v_arg
         c_mask = Constant(int((1<<(8*size2))-1), lltype.Signed)
-        v3 = Variable(); v3.concretetype = lltype.Signed
+        v3 = varoftype(lltype.Signed)
         result.append(SpaceOperation('int_and', [v2, c_mask], v3))
         if min2:
-            result.append(SpaceOperation('int_add', [v3, c_min2], op.result))
+            result.append(SpaceOperation('int_add', [v3, c_min2], v_result))
         else:
-            result[-1].result = op.result
+            result[-1].result = v_result
         return result
 
     def rewrite_op_direct_ptradd(self, op):
@@ -890,30 +934,7 @@
     rewrite_op_ullong_is_true = rewrite_op_llong_is_true
 
     def rewrite_op_cast_primitive(self, op):
-        fromll = longlong.is_longlong(op.args[0].concretetype)
-        toll   = longlong.is_longlong(op.result.concretetype)
-        if fromll != toll:
-            args = op.args
-            if fromll:
-                opname = 'truncate_longlong_to_int'
-                RESULT = lltype.Signed
-            else:
-                from pypy.rpython.lltypesystem import rffi
-                if rffi.cast(op.args[0].concretetype, -1) < 0:
-                    opname = 'cast_int_to_longlong'
-                else:
-                    opname = 'cast_uint_to_longlong'
-                RESULT = lltype.SignedLongLong
-            v = varoftype(RESULT)
-            op1 = SpaceOperation(opname, args, v)
-            op2 = self.rewrite_operation(op1)
-            #
-            # force a renaming to put the correct result in place, even though
-            # it might be slightly mistyped (e.g. Signed versus Unsigned)
-            assert op2.result is v
-            op2.result = op.result
-            #
-            return op2
+        return self.rewrite_op_force_cast(op)
 
     # ----------
     # Renames, from the _old opname to the _new one.
@@ -1247,7 +1268,7 @@
         calldescr = self.callcontrol.getcalldescr(op, oopspecindex,
                                                   extraeffect)
         if extraeffect is not None:
-            assert (type(calldescr) is str      # for tests
+            assert (is_test_calldescr(calldescr)      # for tests
                     or calldescr.get_extra_info().extraeffect == extraeffect)
         if isinstance(op.args[0].value, str):
             pass  # for tests only
@@ -1408,6 +1429,9 @@
         return "using virtualizable array in illegal way in %r" % (
             self.args[0],)
 
+def is_test_calldescr(calldescr):
+    return type(calldescr) is str or getattr(calldescr, '_for_tests_only', False)
+
 def _with_prefix(prefix):
     result = {}
     for name in dir(Transformer):
diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py
--- a/pypy/jit/codewriter/test/test_flatten.py
+++ b/pypy/jit/codewriter/test/test_flatten.py
@@ -3,6 +3,7 @@
 from pypy.jit.codewriter.flatten import flatten_graph, reorder_renaming_list
 from pypy.jit.codewriter.flatten import GraphFlattener, ListOfKind, Register
 from pypy.jit.codewriter.format import assert_format
+from pypy.jit.codewriter import longlong
 from pypy.jit.metainterp.history import AbstractDescr
 from pypy.rpython.lltypesystem import lltype, rclass, rstr
 from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
@@ -30,6 +31,9 @@
             'float': FakeRegAlloc()}
 
 class FakeDescr(AbstractDescr):
+    _for_tests_only = True
+    def __init__(self, oopspecindex=None):
+        self.oopspecindex = oopspecindex
     def __repr__(self):
         return '<Descr>'
     def as_vtable_size_descr(self):
@@ -55,19 +59,24 @@
     def arraydescrof(self, ARRAY):
         return FakeDescr()
 
+class FakeCallInfoCollection:
+    def add(self, *args):
+        pass
+
 class FakeCallControl:
     _descr_cannot_raise = FakeDescr()
+    callinfocollection = FakeCallInfoCollection()
     def guess_call_kind(self, op):
         return 'residual'
-    def getcalldescr(self, op):
+    def getcalldescr(self, op, oopspecindex=None, extraeffect=None):
         try:
             if 'cannot_raise' in op.args[0].value._obj.graph.name:
                 return self._descr_cannot_raise
         except AttributeError:
             pass
-        return FakeDescr()
+        return FakeDescr(oopspecindex)
     def calldescr_canraise(self, calldescr):
-        return calldescr is not self._descr_cannot_raise
+        return calldescr is not self._descr_cannot_raise and calldescr.oopspecindex is None
     def get_vinfo(self, VTYPEPTR):
         return None
 
@@ -734,7 +743,9 @@
 
     def test_force_cast(self):
         from pypy.rpython.lltypesystem import rffi
-
+        # NB: we don't need to test for INT here, the logic in jtransform is
+        # general enough so that if we have the below cases it should
+        # generalize also to INT
         for FROM, TO, expected in [
             (rffi.SIGNEDCHAR, rffi.SIGNEDCHAR, ""),
             (rffi.SIGNEDCHAR, rffi.UCHAR, "int_and %i0, $255 -> %i1"),
@@ -797,14 +808,44 @@
             expected = [s.strip() for s in expected.splitlines()]
             check_force_cast(FROM, TO, expected, 42)
             check_force_cast(FROM, TO, expected, -42)
-            expected.append('int_return %i' + str(len(expected)))
-            expected = '\n'.join(expected)
+            returnvar = "%i" + str(len(expected))
+            expected.append('int_return ' + returnvar)
+            expectedstr = '\n'.join(expected)
             #
             def f(n):
                 return rffi.cast(TO, n)
-            self.encoding_test(f, [rffi.cast(FROM, 42)], expected,
+            self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr,
                                transform=True)
 
+            if not longlong.is_64_bit:
+                if FROM in (rffi.LONG, rffi.ULONG):
+                    if FROM == rffi.LONG:
+                        FROM = rffi.LONGLONG
+                    else:
+                        FROM = rffi.ULONGLONG
+                    expected.insert(0,
+                        "residual_call_irf_i $<* fn llong_to_int>, <Descr>, I[], R[], F[%f0] -> %i0")
+                    expectedstr = '\n'.join(expected)
+                    self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr,
+                                       transform=True)
+                elif TO in (rffi.LONG, rffi.ULONG):
+                    if TO == rffi.LONG:
+                        TO = rffi.LONGLONG
+                    else:
+                        TO = rffi.ULONGLONG
+                    if rffi.cast(FROM, -1) < 0:
+                        fnname = "llong_from_int"
+                    else:
+                        fnname = "llong_from_uint"
+                    expected.pop()   # remove int_return
+                    expected.append(
+                        "residual_call_irf_f $<* fn %s>, <Descr>, I[%s], R[], F[] -> %%f0"
+                        % (fnname, returnvar))
+                    expected.append("float_return %f0")
+                    expectedstr = '\n'.join(expected)
+                    self.encoding_test(f, [rffi.cast(FROM, 42)], expectedstr,
+                                       transform=True)
+
     def test_force_cast_pointer(self):
         from pypy.rpython.lltypesystem import rffi
         def h(p):
@@ -822,6 +863,15 @@
             int_return %i2
         """, transform=True)
 
+    def test_direct_ptradd(self):
+        from pypy.rpython.lltypesystem import rffi
+        def f(p, n):
+            return lltype.direct_ptradd(p, n)
+        self.encoding_test(f, [lltype.nullptr(rffi.CCHARP.TO), 123], """
+            int_add %i0, %i1 -> %i2
+            int_return %i2
+        """, transform=True)
+
 
 def check_force_cast(FROM, TO, operations, value):
     """Check that the test is correctly written..."""
diff --git a/pypy/jit/codewriter/test/test_longlong.py b/pypy/jit/codewriter/test/test_longlong.py
--- a/pypy/jit/codewriter/test/test_longlong.py
+++ b/pypy/jit/codewriter/test/test_longlong.py
@@ -37,7 +37,7 @@
 
 class TestLongLong:
     def setup_class(cls):
-        if sys.maxint > 2147483647:
+        if longlong.is_64_bit:
             py.test.skip("only for 32-bit platforms")
 
     def do_check(self, opname, oopspecindex, ARGS, RESULT):
@@ -46,6 +46,8 @@
         op = SpaceOperation(opname, vlist, v_result)
         tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
         op1 = tr.rewrite_operation(op)
+        if isinstance(op1, list):
+            [op1] = op1
         #
         def is_llf(TYPE):
             return (TYPE == lltype.SignedLongLong or
@@ -196,6 +198,23 @@
             for T2 in [lltype.Signed, lltype.Unsigned]:
                 self.do_check('cast_primitive', EffectInfo.OS_LLONG_TO_INT,
                               [T1], T2)
+                self.do_check('force_cast', EffectInfo.OS_LLONG_TO_INT,
+                              [T1], T2)
+                if T2 == lltype.Signed:
+                    expected = EffectInfo.OS_LLONG_FROM_INT
+                else:
+                    expected = EffectInfo.OS_LLONG_FROM_UINT
+                self.do_check('cast_primitive', expected, [T2], T1)
+                self.do_check('force_cast', expected, [T2], T1)
+        #
+        for T1 in [lltype.SignedLongLong, lltype.UnsignedLongLong]:
+            for T2 in [lltype.SignedLongLong, lltype.UnsignedLongLong]:
+                vlist = [varoftype(T1)]
+                v_result = varoftype(T2)
+                op = SpaceOperation('force_cast', vlist, v_result)
+                tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+                op1 = tr.rewrite_operation(op)
+                assert op1 is None
 
     def test_constants(self):
         for TYPE in [lltype.SignedLongLong, lltype.UnsignedLongLong]:
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -1,5 +1,5 @@
 from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable
-from pypy.interpreter.error import operationerrfmt, OperationError
+from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.rlib import jit
@@ -7,7 +7,6 @@
 from pypy.tool.sourcetools import func_with_new_name
 import math
 
-
 def dummy1(v):
     assert isinstance(v, float)
     return v
@@ -88,23 +87,15 @@
     def _binop_impl(function):
         signature = Signature()
         def impl(self, space, w_other):
+            w_other = convert_to_array(space, w_other)
             new_sig = self.signature.transition(signature)
-            if isinstance(w_other, BaseArray):
-                res = Call2(
-                    function,
-                    self,
-                    w_other,
-                    new_sig.transition(w_other.signature)
-                )
-                w_other.invalidates.append(res)
-            else:
-                w_other = FloatWrapper(space.float_w(w_other))
-                res = Call2(
-                    function,
-                    self,
-                    w_other,
-                    new_sig.transition(w_other.signature)
-                )
+            res = Call2(
+                function,
+                self,
+                w_other,
+                new_sig.transition(w_other.signature)
+            )
+            w_other.invalidates.append(res)
             self.invalidates.append(res)
             return space.wrap(res)
         return func_with_new_name(impl, "binop_%s_impl" % function.__name__)
@@ -272,6 +263,16 @@
     def descr_mean(self, space):
         return space.wrap(space.float_w(self.descr_sum(space))/self.find_size())
 
+def convert_to_array (space, w_obj):
+    if isinstance(w_obj, BaseArray):
+        return w_obj
+    elif space.issequence_w(w_obj):
+        # Convert to array.
+        return new_numarray(space, w_obj)
+    else:
+        # If it's a scalar
+        return FloatWrapper(space.float_w(w_obj))
+
 class FloatWrapper(BaseArray):
     """
     Intermediate class representing a float literal.
@@ -478,14 +479,17 @@
     def __del__(self):
         lltype.free(self.storage, flavor='raw')
 
-def descr_new_numarray(space, w_type, w_size_or_iterable):
+def new_numarray(space, w_size_or_iterable):
     l = space.listview(w_size_or_iterable)
     arr = SingleDimArray(len(l))
     i = 0
     for w_elem in l:
         arr.storage[i] = space.float_w(space.float(w_elem))
         i += 1
-    return space.wrap(arr)
+    return arr
+
+def descr_new_numarray(space, w_type, w_size_or_iterable):
+    return space.wrap(new_numarray(space, w_size_or_iterable))
 
 @unwrap_spec(size=int)
 def zeros(space, size):
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -1,31 +1,35 @@
 import math
 
 from pypy.interpreter.gateway import unwrap_spec
-from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature
+from pypy.module.micronumpy.interp_numarray import BaseArray, Call1, Call2, Signature, convert_to_array
 from pypy.rlib import rfloat
 from pypy.tool.sourcetools import func_with_new_name
 
-
 def ufunc(func):
     signature = Signature()
     def impl(space, w_obj):
-        if isinstance(w_obj, BaseArray):
-            w_res = Call1(func, w_obj, w_obj.signature.transition(signature))
-            w_obj.invalidates.append(w_res)
+        if space.issequence_w(w_obj):
+            w_obj_arr = convert_to_array(space, w_obj)
+            w_res = Call1(func, w_obj_arr, w_obj_arr.signature.transition(signature))
+            w_obj_arr.invalidates.append(w_res)
             return w_res
-        return space.wrap(func(space.float_w(w_obj)))
+        else:
+            return space.wrap(func(space.float_w(w_obj)))
     return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
 
 def ufunc2(func):
     signature = Signature()
     def impl(space, w_lhs, w_rhs):
-        if isinstance(w_lhs, BaseArray) and isinstance(w_rhs, BaseArray):
-            new_sig = w_lhs.signature.transition(signature).transition(w_rhs.signature)
-            w_res = Call2(func, w_lhs, w_rhs, new_sig)
-            w_lhs.invalidates.append(w_res)
-            w_rhs.invalidates.append(w_res)
+        if space.issequence_w(w_lhs) or space.issequence_w(w_rhs):
+            w_lhs_arr = convert_to_array(space, w_lhs)
+            w_rhs_arr = convert_to_array(space, w_rhs)
+            new_sig = w_lhs_arr.signature.transition(signature).transition(w_rhs_arr.signature)
+            w_res = Call2(func, w_lhs_arr, w_rhs_arr, new_sig)
+            w_lhs_arr.invalidates.append(w_res)
+            w_rhs_arr.invalidates.append(w_res)
             return w_res
-        return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs)))
+        else:
+            return space.wrap(func(space.float_w(w_lhs), space.float_w(w_rhs)))
     return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
 
 @ufunc
diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py
--- a/pypy/module/micronumpy/test/test_base.py
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -1,12 +1,10 @@
 from pypy.conftest import gettestobjspace
 from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper
 
-
 class BaseNumpyAppTest(object):
     def setup_class(cls):
         cls.space = gettestobjspace(usemodules=('micronumpy',))
 
-
 class TestSignature(object):
     def test_binop_signature(self, space):
         ar = SingleDimArray(10)
@@ -26,4 +24,4 @@
 
         v3 = ar.descr_add(space, v1)
         v4 = ar.descr_add(space, v2)
-        assert v3.signature is v4.signature
\ No newline at end of file
+        assert v3.signature is v4.signature
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
@@ -97,6 +97,15 @@
         for i in range(5):
             assert b[i] == i + 5
 
+    def test_add_list(self):
+        from numpy import array
+        a = array(range(5))
+        b = list(reversed(range(5)))
+        c = a + b
+        assert isinstance(c, array)
+        for i in range(5):
+            assert c[i] == 4
+
     def test_subtract(self):
         from numpy import array
         a = array(range(5))
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -10,6 +10,40 @@
         assert sign(-0.0) == 0.0
         assert minimum(2.0, 3.0) == 2.0
 
+    def test_sequence(self):
+        from numpy import array, negative, minimum
+        a = array(range(3))
+        b = [2.0, 1.0, 0.0]
+        c = 1.0
+        b_neg = negative(b)
+        assert isinstance(b_neg, array)
+        for i in range(3):
+            assert b_neg[i] == -b[i]
+        min_a_b = minimum(a, b)
+        assert isinstance(min_a_b, array)
+        for i in range(3):
+            assert min_a_b[i] == min(a[i], b[i])
+        min_b_a = minimum(b, a)
+        assert isinstance(min_b_a, array)
+        for i in range(3):
+            assert min_b_a[i] == min(a[i], b[i])
+        min_a_c = minimum(a, c)
+        assert isinstance(min_a_c, array)
+        for i in range(3):
+            assert min_a_c[i] == min(a[i], c)
+        min_c_a = minimum(c, a)
+        assert isinstance(min_c_a, array)
+        for i in range(3):
+            assert min_c_a[i] == min(a[i], c)
+        min_b_c = minimum(b, c)
+        assert isinstance(min_b_c, array)
+        for i in range(3):
+            assert min_b_c[i] == min(b[i], c)
+        min_c_b = minimum(c, b)
+        assert isinstance(min_c_b, array)
+        for i in range(3):
+            assert min_c_b[i] == min(b[i], c)
+
     def test_negative(self):
         from numpy import array, negative
 
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,9 +8,16 @@
 
 class FakeSpace(object):
     w_ValueError = None
+
+    def issequence_w(self, w_obj):
+        return True
+
     @specialize.argtype(1)
-    def wrap(self, v):
-        return v
+    def wrap(self, w_obj):
+        return w_obj
+
+    def float_w(self, w_obj):
+        return float(w_obj)
 
 class TestNumpyJIt(LLJitMixin):
     def setup_class(cls):
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
@@ -134,13 +134,12 @@
 
 
     def test_truncate_python_longs(self):
-        py.test.skip("fixme")
         f = dll._testfunc_i_bhilfd
         f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
         f.restype = c_int
         x = sys.maxint * 2
-        result = f(0, 0, x, 0, 0, 0)
-        assert result == 2
+        result = f(x, x, x, x, 0, 0)
+        assert result == -8
 
 
     def test_floatresult(self):
diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -172,17 +172,6 @@
     assert max_n >= 0
     ITEM = A.OF
     ctypes_item = get_ctypes_type(ITEM, delayed_builders)
-    # Python 2.5 ctypes can raise OverflowError on 64-bit builds
-    for n in [sys.maxint, 2**31]:
-        MAX_SIZE = n/64
-        try:
-            PtrType = ctypes.POINTER(MAX_SIZE * ctypes_item)
-        except OverflowError, e:
-            pass
-        else:
-            break
-    else:
-        raise e
 
     class CArray(ctypes.Structure):
         if not A._hints.get('nolength'):
@@ -191,6 +180,7 @@
         else:
             _fields_ = [('items',  max_n * ctypes_item)]
 
+        @classmethod
         def _malloc(cls, n=None):
             if not isinstance(n, int):
                 raise TypeError, "array length must be an int"
@@ -199,10 +189,29 @@
             if hasattr(bigarray, 'length'):
                 bigarray.length = n
             return bigarray
-        _malloc = classmethod(_malloc)
+
+        _ptrtype = None
+
+        @classmethod
+        def _get_ptrtype(cls):
+            if cls._ptrtype:
+                return cls._ptrtype
+            # ctypes can raise OverflowError on 64-bit builds
+            for n in [sys.maxint, 2**31]:
+                cls.MAX_SIZE = n/64
+                try:
+                    cls._ptrtype = ctypes.POINTER(cls.MAX_SIZE * ctypes_item)
+                except OverflowError, e:
+                    pass
+                else:
+                    break
+            else:
+                raise e
+            return cls._ptrtype
 
         def _indexable(self, index):
-            assert index + 1 < MAX_SIZE
+            PtrType = self._get_ptrtype()
+            assert index + 1 < self.MAX_SIZE
             p = ctypes.cast(ctypes.pointer(self.items), PtrType)
             return p.contents
 
diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
--- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
@@ -671,7 +671,7 @@
         assert not ALLOCATED     # detects memory leaks in the test
 
     def test_arrayofstruct(self):
-        S1 = lltype.Struct('S1', ('x', lltype.Signed))
+        S1 = lltype.Struct('S2', ('x', lltype.Signed))
         A = lltype.Array(S1, hints={'nolength': True})
         a = lltype.malloc(A, 5, flavor='raw')
         a[0].x = 100


More information about the pypy-commit mailing list