[pypy-commit] pypy default: moving ll2ctypes plus tests to default. Not a trivial thing that works

ctismer noreply at buildbot.pypy.org
Wed Mar 14 06:54:06 CET 2012


Author: Christian Tismer <tismer at stackless.com>
Branch: 
Changeset: r53532:4db2ee86e087
Date: 2012-03-13 21:48 -0700
http://bitbucket.org/pypy/pypy/changeset/4db2ee86e087/

Log:	moving ll2ctypes plus tests to default. Not a trivial thing that
	works

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
@@ -14,12 +14,14 @@
 else:
     load_library_kwargs = {}
 
-import os
+import os, platform as host_platform
+from pypy import conftest
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rpython.extfunc import ExtRegistryEntry
 from pypy.rlib.objectmodel import Symbolic, ComputedIntSymbolic
 from pypy.tool.uid import fixid
 from pypy.rlib.rarithmetic import r_singlefloat, r_longfloat, base_int, intmask
+from pypy.rlib.rarithmetic import is_emulated_long, maxint
 from pypy.annotation import model as annmodel
 from pypy.rpython.llinterp import LLInterpreter, LLException
 from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
@@ -32,6 +34,12 @@
     class tlsobject(object):
         pass
 
+_POSIX = os.name == "posix"
+_MS_WINDOWS = os.name == "nt"
+_LINUX = "linux" in sys.platform
+_64BIT = "64bit" in host_platform.architecture()[0]
+
+
 # ____________________________________________________________
 
 far_regions = None
@@ -68,17 +76,22 @@
     global far_regions
     if not far_regions:
         from pypy.rlib import rmmap
-        if sys.maxint > 0x7FFFFFFF:
+        if _64BIT:
             PIECESIZE = 0x80000000
         else:
-            if sys.platform == 'linux':
+            if _LINUX:
                 PIECESIZE = 0x10000000
             else:
                 PIECESIZE = 0x08000000
         PIECES = 10
-        m = rmmap.mmap(-1, PIECES * PIECESIZE,
-                       rmmap.MAP_PRIVATE|rmmap.MAP_ANONYMOUS|rmmap.MAP_NORESERVE,
-                       rmmap.PROT_READ|rmmap.PROT_WRITE)
+        flags = 0
+        if _LINUX:
+            flags = (rmmap.MAP_PRIVATE|rmmap.MAP_ANONYMOUS|rmmap.MAP_NORESERVE,
+                     rmmap.PROT_READ|rmmap.PROT_WRITE)
+        if _MS_WINDOWS:
+            flags = rmmap.MEM_RESERVE
+            # XXX seems not to work
+        m = rmmap.mmap(-1, PIECES * PIECESIZE, flags)
         m.close = lambda : None    # leak instead of giving a spurious
                                    # error at CPython's shutdown
         m._ll2ctypes_pieces = []
@@ -93,9 +106,17 @@
 
 def _setup_ctypes_cache():
     from pypy.rpython.lltypesystem import rffi
+
+    if is_emulated_long:
+        signed_as_ctype = ctypes.c_longlong
+        unsigned_as_ctypes = ctypes.c_ulonglong
+    else:
+        signed_as_ctype = ctypes.c_long
+        unsigned_as_ctypes = ctypes.c_ulong
+
     _ctypes_cache.update({
-        lltype.Signed:   ctypes.c_long,
-        lltype.Unsigned: ctypes.c_ulong,
+        lltype.Signed:   signed_as_ctype,
+        lltype.Unsigned: unsigned_as_ctypes,
         lltype.Char:     ctypes.c_ubyte,
         rffi.DOUBLE:     ctypes.c_double,
         rffi.FLOAT:      ctypes.c_float,
@@ -176,10 +197,26 @@
     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 [maxint, 2**31]:
+        MAX_SIZE = n/64
+        try:
+            PtrType = ctypes.POINTER(MAX_SIZE * ctypes_item)
+        except (OverflowError, AttributeError), e:
+            pass      #        ^^^ bah, blame ctypes
+        else:
+            break
+    else:
+        raise e
 
     class CArray(ctypes.Structure):
+        if is_emulated_long:
+            lentype = ctypes.c_longlong
+        else:
+            lentype = ctypes.c_long
+
         if not A._hints.get('nolength'):
-            _fields_ = [('length', ctypes.c_long),
+            _fields_ = [('length', lentype),
                         ('items',  max_n * ctypes_item)]
         else:
             _fields_ = [('items',  max_n * ctypes_item)]
@@ -201,11 +238,16 @@
             if cls._ptrtype:
                 return cls._ptrtype
             # ctypes can raise OverflowError on 64-bit builds
-            for n in [sys.maxint, 2**31]:
+            # on windows it raises AttributeError even for 2**31 (_length_ missing)
+            if _MS_WINDOWS:
+                other_limit = 2**31-1
+            else:
+                other_limit = 2**31
+            for n in [maxint, other_limit]:
                 cls.MAX_SIZE = n / ctypes.sizeof(ctypes_item)
                 try:
                     cls._ptrtype = ctypes.POINTER(cls.MAX_SIZE * ctypes_item)
-                except OverflowError, e:
+                except (OverflowError, AttributeError), e:
                     pass
                 else:
                     break
@@ -566,7 +608,7 @@
 
     def getbounds(self):
         # we have no clue, so we allow whatever index
-        return 0, sys.maxint
+        return 0, maxint
 
     def getitem(self, index, uninitialized_ok=False):
         res = self._storage.contents._getitem(index, boundscheck=False)
@@ -1326,8 +1368,8 @@
             res = force_cast(lltype.Signed, addr.ptr)
     else:
         res = addr._cast_to_int()
-    if res > sys.maxint:
-        res = res - 2*(sys.maxint + 1)
+    if res > maxint:
+        res = res - 2*(maxint + 1)
         assert int(res) == res
         return int(res)
     return res
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
@@ -16,12 +16,28 @@
 from pypy.rpython.test.test_llinterp import interpret
 from pypy.annotation.annrpython import RPythonAnnotator
 from pypy.rpython.rtyper import RPythonTyper
-
+from pypy.rlib.rarithmetic import r_uint, get_long_pattern, is_emulated_long
+from pypy.rlib.rarithmetic import is_valid_int
 
 if False:    # for now, please keep it False by default
     from pypy.rpython.lltypesystem import ll2ctypes
     ll2ctypes.do_allocation_in_far_regions()
 
+"""
+Win64:
+To decouple the cpython machine level long from the faked integer
+of the target rpython, I replaced most 'lltype.Signed' by 'rffi.LONG'.
+It would be nicer to replace all lltypes constants by rffi equivalents,
+or better if we had a way to address the specific different types of
+the current and the target system layout explicitly.
+Let's think of that when we go further and make the target completely
+independent and configurable.
+Why most and not all replaced?
+Tests with direct tests become cumbersome, instead of direct number
+assignment rffi.setintfield(s, 'x', 123) must be used.
+So in cases with number constants, where the size is not relevant,
+I kept lltype.signed .
+"""
 
 class TestLL2Ctypes(object):
 
@@ -46,15 +62,15 @@
         res = ctypes2lltype(lltype.SingleFloat, ctypes.c_float(-3.5))
         assert isinstance(res, rffi.r_singlefloat)
         assert float(res) == -3.5
-        assert lltype2ctypes(rffi.r_ulong(-1)) == sys.maxint * 2 + 1
+        assert lltype2ctypes(rffi.r_ulong(-1)) == (1 << rffi.r_ulong.BITS) - 1
         res = ctypes2lltype(lltype.Unsigned, sys.maxint * 2 + 1)
-        assert (res, type(res)) == (rffi.r_ulong(-1), rffi.r_ulong)
+        assert (res, type(res)) == (r_uint(-1), r_uint)
         assert ctypes2lltype(lltype.Bool, 0) is False
         assert ctypes2lltype(lltype.Bool, 1) is True
 
-        res = lltype2ctypes(llmemory.sizeof(lltype.Signed))
+        res = lltype2ctypes(llmemory.sizeof(rffi.LONG))
         assert res == struct.calcsize("l")
-        S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed))
+        S = lltype.Struct('S', ('x', rffi.LONG), ('y', rffi.LONG))
         res = lltype2ctypes(llmemory.sizeof(S))
         assert res == struct.calcsize("ll")
 
@@ -69,7 +85,7 @@
     def test_simple_struct(self):
         S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed))
         s = lltype.malloc(S, flavor='raw')
-        s.x = 123
+        rffi.setintfield(s, 'x', 123)
         sc = lltype2ctypes(s)
         assert isinstance(sc.contents, ctypes.Structure)
         assert sc.contents.x == 123
@@ -133,7 +149,11 @@
         ac = lltype2ctypes(a, normalize=False)
         assert isinstance(ac.contents, ctypes.Structure)
         assert ac.contents.length == 10
-        assert ac.contents._fields_[0] == ('length', ctypes.c_long)
+        if is_emulated_long:
+            lentype = ctypes.c_longlong
+        else:
+            lentype = ctypes.c_long
+        assert ac.contents._fields_[0] == ('length', lentype)
         assert ac.contents.items[1] == 101
         ac.contents.items[2] = 456
         assert a[2] == 456
@@ -144,7 +164,7 @@
 
     def test_array_inside_struct(self):
         # like rstr.STR, but not Gc
-        STR = lltype.Struct('STR', ('x', lltype.Signed), ('y', lltype.Array(lltype.Char)))
+        STR = lltype.Struct('STR', ('x', rffi.LONG), ('y', lltype.Array(lltype.Char)))
         a = lltype.malloc(STR, 3, flavor='raw')
         a.y[0] = 'x'
         a.y[1] = 'y'
@@ -171,7 +191,7 @@
         assert a[2] == 456
         a[3] = 789
         assert ac.contents.items[3] == 789
-        assert ctypes.sizeof(ac.contents) == 10 * ctypes.sizeof(ctypes.c_long)
+        assert ctypes.sizeof(ac.contents) == 10 * rffi.sizeof(lltype.Signed)
         lltype.free(a, flavor='raw')
         assert not ALLOCATED     # detects memory leaks in the test
 
@@ -223,20 +243,20 @@
 
     def test_func_not_in_clib(self):
         eci = ExternalCompilationInfo(libraries=['m'])
-        foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed)
+        foobar = rffi.llexternal('I_really_dont_exist', [], rffi.LONG)
         py.test.raises(NotImplementedError, foobar)
 
-        foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed,
+        foobar = rffi.llexternal('I_really_dont_exist', [], rffi.LONG,
                                  compilation_info=eci)    # math library
         py.test.raises(NotImplementedError, foobar)
 
         eci = ExternalCompilationInfo(libraries=['m', 'z'])
-        foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed,
+        foobar = rffi.llexternal('I_really_dont_exist', [], rffi.LONG,
                                  compilation_info=eci)  # math and zlib
         py.test.raises(NotImplementedError, foobar)
 
         eci = ExternalCompilationInfo(libraries=['I_really_dont_exist_either'])
-        foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed,
+        foobar = rffi.llexternal('I_really_dont_exist', [], rffi.LONG,
                                  compilation_info=eci)
         py.test.raises(NotImplementedError, foobar)
         assert not ALLOCATED     # detects memory leaks in the test
@@ -399,10 +419,9 @@
 
         b = rffi.cast(lltype.Ptr(B), a)
 
-        checker = array.array('l')
+        expected = ''
         for i in range(10):
-            checker.append(i*i)
-        expected = checker.tostring()
+            expected += get_long_pattern(i*i)
 
         for i in range(len(expected)):
             assert b[i] == expected[i]
@@ -418,7 +437,7 @@
             assert e[i] == i*i
 
         c = lltype.nullptr(rffi.VOIDP.TO)
-        addr = rffi.cast(lltype.Signed, c)
+        addr = rffi.cast(rffi.LONG, c)
         assert addr == 0
 
         lltype.free(a, flavor='raw')
@@ -444,8 +463,13 @@
 
         FUNCTYPE = lltype.FuncType([lltype.Signed], lltype.Signed)
         cdummy = lltype2ctypes(llhelper(lltype.Ptr(FUNCTYPE), dummy))
-        assert isinstance(cdummy,
-                          ctypes.CFUNCTYPE(ctypes.c_long, ctypes.c_long))
+        if not is_emulated_long:
+            assert isinstance(cdummy,
+                              ctypes.CFUNCTYPE(ctypes.c_long, ctypes.c_long))
+        else:
+            # XXX maybe we skip this if it breaks on some platforms
+            assert isinstance(cdummy,
+                              ctypes.CFUNCTYPE(ctypes.c_longlong, ctypes.c_longlong))
         res = cdummy(41)
         assert res == 42
         lldummy = ctypes2lltype(lltype.Ptr(FUNCTYPE), cdummy)
@@ -455,7 +479,7 @@
         assert not ALLOCATED     # detects memory leaks in the test
 
     def test_funcptr2(self):
-        FUNCTYPE = lltype.FuncType([rffi.CCHARP], lltype.Signed)
+        FUNCTYPE = lltype.FuncType([rffi.CCHARP], rffi.LONG)
         cstrlen = standard_c_lib.strlen
         llstrlen = ctypes2lltype(lltype.Ptr(FUNCTYPE), cstrlen)
         assert lltype.typeOf(llstrlen) == lltype.Ptr(FUNCTYPE)
@@ -545,8 +569,9 @@
 
         checkval(uninitialized2ctypes(rffi.CHAR), 'B')
         checkval(uninitialized2ctypes(rffi.SHORT), 'h')
-        checkval(uninitialized2ctypes(rffi.INT), 'i')
-        checkval(uninitialized2ctypes(rffi.UINT), 'I')
+        if not is_emulated_long:
+            checkval(uninitialized2ctypes(rffi.INT), 'i')
+            checkval(uninitialized2ctypes(rffi.UINT), 'I')
         checkval(uninitialized2ctypes(rffi.LONGLONG), 'q')
         checkval(uninitialized2ctypes(rffi.DOUBLE), 'd')
         checkobj(uninitialized2ctypes(rffi.INTP),
@@ -554,7 +579,7 @@
         checkobj(uninitialized2ctypes(rffi.CCHARP),
                  ctypes.sizeof(ctypes.c_void_p))
 
-        S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed))
+        S = lltype.Struct('S', ('x', rffi.LONG), ('y', rffi.LONG))
         s = lltype.malloc(S, flavor='raw')
         sc = lltype2ctypes(s)
         checkval(sc.contents.x, 'l')
@@ -717,9 +742,13 @@
         assert not ALLOCATED     # detects memory leaks in the test
 
     def test_get_errno(self):
+        # win64: works with python 2.6.7, but not with 2.7.2
+        # XXX check what is different with ctypes!
         eci = ExternalCompilationInfo(includes=['string.h'])
         if sys.platform.startswith('win'):
             underscore_on_windows = '_'
+            if sys.version.startswith('2.7.2 '):
+                py.test.skip('ctypes is buggy. errno crashes with win64 and python 2.7.2')
         else:
             underscore_on_windows = ''
         strlen = rffi.llexternal('strlen', [rffi.CCHARP], rffi.SIZE_T,
@@ -730,7 +759,7 @@
         buffer = lltype.malloc(rffi.CCHARP.TO, 5, flavor='raw')
         written = os_write(12312312, buffer, 5)
         lltype.free(buffer, flavor='raw')
-        assert rffi.cast(lltype.Signed, written) < 0
+        assert rffi.cast(rffi.LONG, written) < 0
         # the next line is a random external function call,
         # to check that it doesn't reset errno
         strlen("hi!")
@@ -849,9 +878,9 @@
             return one + get_x()
 
         def fy():
-            one = rffi.cast(lltype.Signed, get_y())
+            one = rffi.cast(rffi.LONG, get_y())
             set_y(rffi.cast(rffi.INT, 13))
-            return one + rffi.cast(lltype.Signed, get_y())
+            return one + rffi.cast(rffi.LONG, get_y())
 
         def g():
             l = rffi.liststr2charpp(["a", "b", "c"])
@@ -916,7 +945,7 @@
         lltype.free(a, flavor='raw')
 
     def test_array_type_bug(self):
-        A = lltype.Array(lltype.Signed)
+        A = lltype.Array(rffi.LONG)
         a1 = lltype.malloc(A, 0, flavor='raw')
         a2 = lltype.malloc(A, 0, flavor='raw')
         c1 = lltype2ctypes(a1)
@@ -1006,7 +1035,7 @@
 
     def test_recursive_struct_more(self):
         NODE = lltype.ForwardReference()
-        NODE.become(lltype.Struct('NODE', ('value', lltype.Signed),
+        NODE.become(lltype.Struct('NODE', ('value', rffi.LONG),
                                           ('next', lltype.Ptr(NODE))))
         CNODEPTR = get_ctypes_type(NODE)
         pc = CNODEPTR()
@@ -1034,11 +1063,11 @@
         assert p.pong.ping == p
 
     def test_typedef(self):
-        assert ctypes2lltype(lltype.Typedef(lltype.Signed, 'test'), 6) == 6
+        assert ctypes2lltype(lltype.Typedef(rffi.LONG, 'test'), 6) == 6
         assert ctypes2lltype(lltype.Typedef(lltype.Float, 'test2'), 3.4) == 3.4
 
-        assert get_ctypes_type(lltype.Signed) == get_ctypes_type(
-            lltype.Typedef(lltype.Signed, 'test3'))
+        assert get_ctypes_type(rffi.LONG) == get_ctypes_type(
+            lltype.Typedef(rffi.LONG, 'test3'))
 
     def test_cast_adr_to_int(self):
         class someaddr(object):
@@ -1046,7 +1075,7 @@
                 return sys.maxint/2 * 3
 
         res = cast_adr_to_int(someaddr())
-        assert isinstance(res, int)
+        assert is_valid_int(res)
         assert res == -sys.maxint/2 - 3
 
     def test_cast_gcref_back_and_forth(self):
@@ -1299,7 +1328,7 @@
         p = lltype.malloc(S, flavor='raw')
         a = llmemory.cast_ptr_to_adr(p)
         i = llmemory.cast_adr_to_int(a, "forced")
-        assert type(i) is int
+        assert is_valid_int(i)
         assert i == llmemory.cast_adr_to_int(a, "forced")
         lltype.free(p, flavor='raw')
 


More information about the pypy-commit mailing list