[pypy-svn] r72464 - in pypy/branch/rawffi-64/pypy/module/_rawffi: . test

arigo at codespeak.net arigo at codespeak.net
Sat Mar 20 18:56:13 CET 2010


Author: arigo
Date: Sat Mar 20 18:56:11 2010
New Revision: 72464

Modified:
   pypy/branch/rawffi-64/pypy/module/_rawffi/array.py
   pypy/branch/rawffi-64/pypy/module/_rawffi/interp_rawffi.py
   pypy/branch/rawffi-64/pypy/module/_rawffi/structure.py
   pypy/branch/rawffi-64/pypy/module/_rawffi/test/test__rawffi.py
Log:
Whack whack until one test passes.


Modified: pypy/branch/rawffi-64/pypy/module/_rawffi/array.py
==============================================================================
--- pypy/branch/rawffi-64/pypy/module/_rawffi/array.py	(original)
+++ pypy/branch/rawffi-64/pypy/module/_rawffi/array.py	Sat Mar 20 18:56:11 2010
@@ -12,8 +12,8 @@
 from pypy.module._rawffi.interp_rawffi import segfault_exception
 from pypy.module._rawffi.interp_rawffi import W_DataShape, W_DataInstance
 from pypy.module._rawffi.interp_rawffi import unwrap_value, wrap_value
-from pypy.module._rawffi.interp_rawffi import letter2tp
-from pypy.module._rawffi.interp_rawffi import unpack_to_size_alignment
+from pypy.module._rawffi.interp_rawffi import TYPEMAP
+from pypy.module._rawffi.interp_rawffi import unpack_shape_with_length
 from pypy.rlib.rarithmetic import intmask, r_uint
 
 def push_elem(ll_array, pos, value):
@@ -27,17 +27,30 @@
     return ll_array[pos]
 get_elem._annspecialcase_ = 'specialize:arg(2)'
 
+
 class W_Array(W_DataShape):
-    def __init__(self, space, itemtp):
-        assert isinstance(itemtp, tuple)
-        self.space = space
-        self.itemtp = itemtp
+    def __init__(self, basicffitype, multiplier=1, itemcode='?'):
+        # 'multiplier' is not the length of the array!
+        # A W_Array represent the C type '*T', which can also represent
+        # the type of pointers to arrays of T.  So the following fields
+        # are used to describe T only.  It is 'multiplier' times the
+        # 'basicffitype'.
+        self.basicffitype = basicffitype
+        self.multiplier = multiplier
+        # for the W_Arrays that represent simple types only:
+        self.itemcode = itemcode
 
     def allocate(self, space, length, autofree=False):
         if autofree:
             return W_ArrayInstanceAutoFree(space, self, length)
         return W_ArrayInstance(space, self, length)
 
+    def get_basic_ffi_type(self):
+        return self.basicffitype
+
+    def get_ffi_type_with_length(self):
+        return self.basicffitype, self.multiplier
+
     def descr_call(self, space, length, w_items=None, autofree=False):
         result = self.allocate(space, length, autofree)
         if not space.is_w(w_items, space.w_None):
@@ -50,42 +63,34 @@
             for num in range(iterlength):
                 w_item = items_w[num]
                 unwrap_value(space, push_elem, result.ll_buffer, num,
-                             self.itemtp[0], w_item)
+                             self.itemcode, w_item)
         return space.wrap(result)
 
     def descr_repr(self, space):
-        return space.wrap("<_rawffi.Array '%s' (%d, %d)>" % self.itemtp)
+        return space.wrap("<_rawffi.Array '%s' (%d, %d)>" % self.itemcode)
     descr_repr.unwrap_spec = ['self', ObjSpace]
 
     def fromaddress(self, space, address, length):
         return space.wrap(W_ArrayInstance(space, self, length, address))
     fromaddress.unwrap_spec = ['self', ObjSpace, r_uint, int]
 
-    def _size_alignment(self):
-        _, itemsize, alignment = self.itemtp
-        return itemsize, alignment
-
-class ArrayCache:
-    def __init__(self, space):
-        self.space = space
-        self.cache = {}
-        self.array_of_ptr = self.get_array_type(letter2tp(space, 'P'))
-
-    def get_array_type(self, itemtp):
-        try:
-            return self.cache[itemtp]
-        except KeyError:
-            result = W_Array(self.space, itemtp)
-            self.cache[itemtp] = result
-            return result
-
-def get_array_cache(space):
-    return space.fromcache(ArrayCache)
+PRIMITIVE_ARRAY_TYPES = {}
+for _code in TYPEMAP:
+    PRIMITIVE_ARRAY_TYPES[_code] = W_Array(TYPEMAP[_code], itemcode=_code)
+ARRAY_OF_PTRS = PRIMITIVE_ARRAY_TYPES['P']
 
 def descr_new_array(space, w_type, w_shape):
-    itemtp = unpack_to_size_alignment(space, w_shape)
-    array_type = get_array_cache(space).get_array_type(itemtp)
-    return space.wrap(array_type)
+    shape, length = unpack_shape_with_length(space, w_shape)
+    if length == 1:
+        return shape
+    if shape._array_shapes is None:
+        shape._array_shapes = {}
+    try:
+        result = shape._array_shapes[length]
+    except KeyError:
+        ffitype, lbase = shape.get_ffi_type_with_length()
+        result = shape._array_shapes[length] = W_Array(ffitype, lbase*length)
+    return result
 
 W_Array.typedef = TypeDef(
     'Array',
@@ -102,8 +107,7 @@
 
 class W_ArrayInstance(W_DataInstance):
     def __init__(self, space, shape, length, address=r_uint(0)):
-        _, itemsize, _ = shape.itemtp
-        W_DataInstance.__init__(self, space, itemsize * length, address)
+        W_DataInstance.__init__(self, space, shape.size * length, address)
         self.length = length
         self.shape = shape
 
@@ -122,7 +126,7 @@
         if num >= self.length or num < 0:
             raise OperationError(space.w_IndexError, space.w_None)
         unwrap_value(space, push_elem, self.ll_buffer, num,
-                     self.shape.itemtp[0], w_value)
+                     self.shape.itemcode, w_value)
 
     def descr_setitem(self, space, w_index, w_value):
         try:
@@ -141,7 +145,7 @@
         if num >= self.length or num < 0:
             raise OperationError(space.w_IndexError, space.w_None)
         return wrap_value(space, get_elem, self.ll_buffer, num,
-                          self.shape.itemtp)
+                          self.shape.itemcode)
 
     def descr_getitem(self, space, w_index):
         try:

Modified: pypy/branch/rawffi-64/pypy/module/_rawffi/interp_rawffi.py
==============================================================================
--- pypy/branch/rawffi-64/pypy/module/_rawffi/interp_rawffi.py	(original)
+++ pypy/branch/rawffi-64/pypy/module/_rawffi/interp_rawffi.py	Sat Mar 20 18:56:11 2010
@@ -52,9 +52,6 @@
 def size_alignment(ffi_type):
     return intmask(ffi_type.c_size), intmask(ffi_type.c_alignment)
 
-UNPACKED_TYPECODES = dict([(code, (code,) + size_alignment(field_desc))
-                           for code, field_desc in TYPEMAP.items()])
-
 LL_TYPEMAP = {
     'c' : rffi.CHAR,
     'u' : lltype.UniChar,
@@ -82,65 +79,41 @@
     LL_TYPEMAP['v'] = rffi.SHORT
 
 def letter2tp(space, key):
+    from pypy.module._rawffi.array import PRIMITIVE_ARRAY_TYPES
     try:
-        return UNPACKED_TYPECODES[key]
+        return PRIMITIVE_ARRAY_TYPES[key]
     except KeyError:
         raise operationerrfmt(space.w_ValueError,
                               "Unknown type letter %s", key)
 
-def _get_type_(space, key):
-    try:
-        return TYPEMAP[key]
-    except KeyError:
-        raise operationerrfmt(space.w_ValueError,
-                              "Unknown type letter %s", key)
-    
-def unpack_to_ffi_type(space, w_shape, shape=False):
-    resshape = None
+def unpack_simple_shape(space, w_shape):
+    # 'w_shape' must be either a letter or a tuple (struct, 1).
     if space.is_true(space.isinstance(w_shape, space.w_str)):
         letter = space.str_w(w_shape)
-        ffi_type = _get_type_(space, letter)
-        if shape:
-            from pypy.module._rawffi.array import get_array_cache
-            cache = get_array_cache(space)
-            resshape = cache.get_array_type(letter2tp(space, letter))
+        return letter2tp(space, letter)
     else:
-        letter = 'V'
         w_shapetype, w_length = space.fixedview(w_shape, expected_length=2)
         from pypy.module._rawffi.structure import W_Structure
-        resshape = space.interp_w(W_Structure, w_shapetype)
-        ffi_type = resshape.get_ffi_type()
-    return letter, ffi_type, resshape
+        return space.interp_w(W_Structure, w_shapetype)
 
-def unpack_to_size_alignment(space, w_shape):
+def unpack_shape_with_length(space, w_shape):
+    # allow 'w_shape' to be a letter or any (shape, number).
     if space.is_true(space.isinstance(w_shape, space.w_str)):
         letter = space.str_w(w_shape)
-        return letter2tp(space, letter)
+        return letter2tp(space, letter), 1
     else:
         w_shapetype, w_length = space.fixedview(w_shape, expected_length=2)
-        resshape = space.interp_w(W_DataShape, w_shapetype)
         length = space.int_w(w_length)
-        size, alignment = resshape._size_alignment()
-        return ('V', length*size, alignment) # value object
+        return space.interp_w(W_DataShape, w_shapetype), length
 
 def unpack_resshape(space, w_restype):
     if space.is_w(w_restype, space.w_None):
-        resshape = None
-        ffi_restype = ffi_type_void
-    else:
-        tp_letter, ffi_restype, resshape = unpack_to_ffi_type(space,
-                                                    w_restype,
-                                                    shape=True)
-    return ffi_restype, resshape
+        return None
+    return unpack_simple_shape(space, w_restype)
 
 def unpack_argshapes(space, w_argtypes):
-    argletters = []
-    ffi_argtypes = []
-    for w_arg in space.unpackiterable(w_argtypes):
-        argletter, ffi_argtype, _ = unpack_to_ffi_type(space, w_arg)
-        argletters.append(argletter)
-        ffi_argtypes.append(ffi_argtype)
-    return ffi_argtypes, argletters
+    return [unpack_simple_shape(space, w_arg)
+            for w_arg in space.unpackiterable(w_argtypes)]
 
 class W_CDLL(Wrappable):
     def __init__(self, space, name):
@@ -157,7 +130,7 @@
         """ Get a pointer for function name with provided argtypes
         and restype
         """
-        ffi_restype, resshape = unpack_resshape(space, w_restype)
+        resshape = unpack_resshape(space, w_restype)
         w = space.wrap
         argtypes_w = space.fixedview(w_argtypes)
         w_argtypes = space.newtuple(argtypes_w)
@@ -169,7 +142,12 @@
                 pass
             else:
                 raise
-        ffi_argtypes, argletters = unpack_argshapes(space, w_argtypes)
+        argshapes = unpack_argshapes(space, w_argtypes)
+        ffi_argtypes = [shape.get_basic_ffi_type() for shape in argshapes]
+        if resshape is not None:
+            ffi_restype = resshape.get_basic_ffi_type()
+        else:
+            ffi_restype = ffi_type_void
 
         if space.is_true(space.isinstance(w_name, space.w_str)):
             name = space.str_w(w_name)
@@ -194,7 +172,7 @@
             raise OperationError(space.w_TypeError, space.wrap(
                 "function name must be string or integer"))
 
-        w_funcptr = W_FuncPtr(space, ptr, argletters, resshape)
+        w_funcptr = W_FuncPtr(space, ptr, argshapes, resshape)
         space.setitem(self.w_cache, w_key, w_funcptr)
         return w_funcptr
     ptr.unwrap_spec = ['self', ObjSpace, W_Root, W_Root, W_Root, int]
@@ -240,17 +218,22 @@
     return OperationError(w_exception, space.wrap(reason))
 
 class W_DataShape(Wrappable):
+    _array_shapes = None
+    size = 0
+    alignment = 0
     
     def allocate(self, space, length, autofree=False):
         raise NotImplementedError
 
-    def _size_alignment(self):
+    def get_basic_ffi_type(self):
         raise NotImplementedError
-    
+
+    def get_ffi_type_with_length(self):
+        return self.get_basic_ffi_type(), 1     # default implementation
+
     def descr_size_alignment(self, space, n=1):
-        size, alignment = self._size_alignment()
-        return space.newtuple([space.wrap(size * n),
-                               space.wrap(alignment)])
+        return space.newtuple([space.wrap(self.size * n),
+                               space.wrap(self.alignment)])
     descr_size_alignment.unwrap_spec = ['self', ObjSpace, int]
     
 
@@ -269,9 +252,8 @@
         return space.wrap(rffi.cast(lltype.Unsigned, self.ll_buffer))
 
     def byptr(self, space):
-        from pypy.module._rawffi.array import get_array_cache
-        array_of_ptr = get_array_cache(space).array_of_ptr
-        array = array_of_ptr.allocate(space, 1)
+        from pypy.module._rawffi.array import ARRAY_OF_PTRS
+        array = ARRAY_OF_PTRS.allocate(space, 1)
         array.setitem(space, 0, space.wrap(self))
         return space.wrap(array)
     byptr.unwrap_spec = ['self', ObjSpace]
@@ -306,12 +288,7 @@
 
 def unwrap_value(space, push_func, add_arg, argdesc, letter, w_arg):
     w = space.wrap
-    if letter == "d":
-        push_func(add_arg, argdesc, space.float_w(w_arg))
-    elif letter == "f":
-        push_func(add_arg, argdesc, rffi.cast(rffi.FLOAT,
-                                              space.float_w(w_arg)))
-    elif letter in TYPEMAP_PTR_LETTERS:
+    if letter in TYPEMAP_PTR_LETTERS:
         # check for NULL ptr
         datainstance = space.interpclass_w(w_arg)
         if isinstance(datainstance, W_DataInstance):
@@ -319,6 +296,11 @@
         else:
             ptr = unwrap_truncate_int(rffi.VOIDP, space, w_arg)
         push_func(add_arg, argdesc, ptr)
+    elif letter == "d":
+        push_func(add_arg, argdesc, space.float_w(w_arg))
+    elif letter == "f":
+        push_func(add_arg, argdesc, rffi.cast(rffi.FLOAT,
+                                              space.float_w(w_arg)))
     elif letter == "c":
         s = space.str_w(w_arg)
         if len(s) != 1:
@@ -347,8 +329,7 @@
 
 ll_typemap_iter = unrolling_iterable(LL_TYPEMAP.items())
 
-def wrap_value(space, func, add_arg, argdesc, tp):
-    letter, _, _ = tp
+def wrap_value(space, func, add_arg, argdesc, letter):
     for c, ll_type in ll_typemap_iter:
         if letter == c:
             if c in TYPEMAP_PTR_LETTERS:
@@ -365,9 +346,9 @@
 wrap_value._annspecialcase_ = 'specialize:arg(1)'
 
 class W_FuncPtr(Wrappable):
-    def __init__(self, space, ptr, argletters, resshape):
+    def __init__(self, space, ptr, argshapes, resshape):
         self.ptr = ptr
-        self.argletters = argletters
+        self.argshapes = argshapes
         self.resshape = resshape
 
     def getbuffer(space, self):
@@ -393,16 +374,17 @@
     def call(self, space, args_w):
         from pypy.module._rawffi.array import W_ArrayInstance
         from pypy.module._rawffi.structure import W_StructureInstance
+        from pypy.module._rawffi.structure import W_Structure
         argnum = len(args_w)
-        if argnum != len(self.argletters):
+        if argnum != len(self.argshapes):
             msg = "Wrong number of arguments: expected %d, got %d"
             raise operationerrfmt(space.w_TypeError, msg,
-                                  len(self.argletters), argnum)
+                                  len(self.argshapes), argnum)
         args_ll = []
         for i in range(argnum):
-            argletter = self.argletters[i]
+            argshape = self.argshapes[i]
             w_arg = args_w[i]
-            if argletter == 'V': # by value object
+            if isinstance(argshape, W_Structure):   # argument by value
                 arg = space.interp_w(W_StructureInstance, w_arg)
                 xsize, xalignment = size_alignment(self.ptr.argtypes[i])
                 if (arg.shape.size != xsize or
@@ -420,7 +402,8 @@
                            "got length %d")
                     raise operationerrfmt(space.w_TypeError, msg,
                                           i+1, arg.length)
-                letter = arg.shape.itemtp[0]
+                argletter = argshape.itemcode
+                letter = arg.shape.itemcode
                 if letter != argletter:
                     if not (argletter in TYPEMAP_PTR_LETTERS and
                             letter in TYPEMAP_PTR_LETTERS):

Modified: pypy/branch/rawffi-64/pypy/module/_rawffi/structure.py
==============================================================================
--- pypy/branch/rawffi-64/pypy/module/_rawffi/structure.py	(original)
+++ pypy/branch/rawffi-64/pypy/module/_rawffi/structure.py	Sat Mar 20 18:56:11 2010
@@ -13,7 +13,7 @@
 from pypy.module._rawffi.interp_rawffi import segfault_exception
 from pypy.module._rawffi.interp_rawffi import W_DataShape, W_DataInstance
 from pypy.module._rawffi.interp_rawffi import wrap_value, unwrap_value
-from pypy.module._rawffi.interp_rawffi import unpack_to_size_alignment
+#from pypy.module._rawffi.interp_rawffi import unpack_to_size_alignment
 from pypy.rlib import libffi
 from pypy.rlib.rarithmetic import intmask, r_uint
 
@@ -99,13 +99,10 @@
         return space.wrap(self.ll_positions[index])
     descr_fieldoffset.unwrap_spec = ['self', ObjSpace, str]
 
-    def _size_alignment(self):
-        return self.size, self.alignment
-
     # get the corresponding ffi_type
     ffi_type = lltype.nullptr(libffi.FFI_TYPE_P.TO)
 
-    def get_ffi_type(self):
+    def get_basic_ffi_type(self):
         if not self.ffi_type:
             self.ffi_type = libffi.make_struct_ffitype(self.size,
                                                        self.alignment)

Modified: pypy/branch/rawffi-64/pypy/module/_rawffi/test/test__rawffi.py
==============================================================================
--- pypy/branch/rawffi-64/pypy/module/_rawffi/test/test__rawffi.py	(original)
+++ pypy/branch/rawffi-64/pypy/module/_rawffi/test/test__rawffi.py	Sat Mar 20 18:56:11 2010
@@ -141,6 +141,16 @@
             return inp;
         }
 
+        struct s2a {
+            int bah[2];
+        };
+
+        struct s2a perturbarray(struct s2a inp) {
+            inp.bah[0] *= 4;
+            inp.bah[1] *= 5;
+            return inp;
+        }
+
         int AAA_first_ordinal_function()
         {
             return 42;
@@ -157,7 +167,7 @@
                      allocate_array
                      static_int static_double
                      sum_x_y
-                     give perturb
+                     give perturb perturbarray
                      AAA_first_ordinal_function
                   """.split()
         eci = ExternalCompilationInfo(export_symbols=symbols)
@@ -819,19 +829,22 @@
             assert 0, "Did not raise"
 
     def test_struct_byvalue(self):
-        if self.isx86_64:
-            skip("Segfaults on x86_64 because small structures "
-                 "may be passed in registers and "
-                 "c_elements must not be null")
+        #if self.isx86_64:
+        #    skip("Segfaults on x86_64 because small structures "
+        #         "may be passed in registers and "
+        #         "c_elements must not be null")
 
-        import _rawffi
+        import _rawffi, sys
         X_Y = _rawffi.Structure([('x', 'l'), ('y', 'l')])
         x_y = X_Y()
         lib = _rawffi.CDLL(self.lib_name)
+        print >> sys.stderr, "getting..."
         sum_x_y = lib.ptr('sum_x_y', [(X_Y, 1)], 'l')
         x_y.x = 200
         x_y.y = 220
+        print >> sys.stderr, "calling..."
         res = sum_x_y(x_y)
+        print >> sys.stderr, "done"
         assert res[0] == 420
         x_y.free()
 
@@ -871,6 +884,41 @@
         
         s2h.free()
 
+    def test_ret_struct_containing_array(self):
+        if self.isx86_64:
+            skip("Segfaults on x86_64 because small structures "
+                 "may be passed in registers and "
+                 "c_elements must not be null")
+
+        import _rawffi
+        AoI = _rawffi.Array('i')
+        S2A = _rawffi.Structure([('bah', (AoI, 2))])
+        s2a = S2A()
+        lib = _rawffi.CDLL(self.lib_name)
+        perturbarray = lib.ptr('perturbarray', [(S2A, 1)], (S2A, 1))
+        s2a.x = 100
+        a2a.y = 200
+        res = perturbarray(s2a)
+        assert isinstance(res, _rawffi.StructureInstanceAutoFree)
+        assert res.shape is S2H
+        assert res.x == 13
+        assert res.y == 17
+        a1.free()
+        a2.free()
+
+        s2h.x = 7
+        s2h.y = 11
+        perturb = lib.ptr('perturb', [(S2H, 1)], (S2H, 1))
+        res = perturb(s2h)
+        assert isinstance(res, _rawffi.StructureInstanceAutoFree)
+        assert res.shape is S2H
+        assert res.x == 14
+        assert res.y == 33
+        assert s2h.x == 7
+        assert s2h.y == 11
+        
+        s2h.free()
+
     def test_buffer(self):
         import _rawffi
         S = _rawffi.Structure((40, 1))



More information about the Pypy-commit mailing list