[pypy-svn] r51791 - in pypy/dist/pypy: lib/_ctypes lib/app_test/ctypes module/_rawffi module/_rawffi/test rlib rlib/test

pedronis at codespeak.net pedronis at codespeak.net
Fri Feb 22 15:57:23 CET 2008


Author: pedronis
Date: Fri Feb 22 15:57:21 2008
New Revision: 51791

Modified:
   pypy/dist/pypy/lib/_ctypes/structure.py
   pypy/dist/pypy/lib/app_test/ctypes/test_as_parameter.py
   pypy/dist/pypy/lib/app_test/ctypes/test_functions.py
   pypy/dist/pypy/module/_rawffi/interp_rawffi.py
   pypy/dist/pypy/module/_rawffi/test/test__rawffi.py
   pypy/dist/pypy/rlib/libffi.py
   pypy/dist/pypy/rlib/test/test_libffi.py
Log:
Passing structure as values to functions.

_ffiletter is probably not anymore the right name for this.

This leaks ffitypes at the moment, given that for some ABIs we really need
the completely filled ffitype we may want to approach this by having gettypecode
return something that contains a full ffitype for the structure(/array) type,
instead of the current tuple. The type would own its ffitype then.



Modified: pypy/dist/pypy/lib/_ctypes/structure.py
==============================================================================
--- pypy/dist/pypy/lib/_ctypes/structure.py	(original)
+++ pypy/dist/pypy/lib/_ctypes/structure.py	Fri Feb 22 15:57:21 2008
@@ -106,6 +106,7 @@
                 typedict.get('_anonymous_', None))
             res._ffistruct = _rawffi.Structure(rawfields)
             res._ffishape = res._ffistruct.gettypecode()
+            res._ffiletter = res._ffishape
 
         def __init__(self, *args, **kwds):
             if not hasattr(self, '_ffistruct'):
@@ -158,7 +159,6 @@
 
 class Structure(_CData):
     __metaclass__ = StructureMeta
-    _ffiletter = 'P'
     _needs_free = False
 
     def _subarray(self, fieldtype, name):
@@ -196,7 +196,7 @@
         return fieldtype._CData_output(suba, self, offset)
 
     def _get_buffer_for_param(self):
-        return CArgObject(self._buffer.byptr())
+        return self
 
     def _get_buffer_value(self):
         return self._buffer.buffer

Modified: pypy/dist/pypy/lib/app_test/ctypes/test_as_parameter.py
==============================================================================
--- pypy/dist/pypy/lib/app_test/ctypes/test_as_parameter.py	(original)
+++ pypy/dist/pypy/lib/app_test/ctypes/test_as_parameter.py	Fri Feb 22 15:57:21 2008
@@ -144,7 +144,6 @@
         assert 13577625587 == int(f(self.wrap(1000000000000), self.wrap(cb)))
 
     def test_byval(self):
-        py.test.skip("Structure by value")
         # without prototype
         ptin = POINT(1, 2)
         ptout = POINT()

Modified: pypy/dist/pypy/lib/app_test/ctypes/test_functions.py
==============================================================================
--- pypy/dist/pypy/lib/app_test/ctypes/test_functions.py	(original)
+++ pypy/dist/pypy/lib/app_test/ctypes/test_functions.py	Fri Feb 22 15:57:21 2008
@@ -310,7 +310,6 @@
         raises(ValueError, c_int.in_dll, dll, "_xxx_yyy")
 
     def test_byval(self):
-        py.test.skip("Structure by value")
         # without prototype
         ptin = POINT(1, 2)
         ptout = POINT()

Modified: pypy/dist/pypy/module/_rawffi/interp_rawffi.py
==============================================================================
--- pypy/dist/pypy/module/_rawffi/interp_rawffi.py	(original)
+++ pypy/dist/pypy/module/_rawffi/interp_rawffi.py	Fri Feb 22 15:57:21 2008
@@ -86,6 +86,14 @@
         raise OperationError(space.w_ValueError, space.wrap(
             "Unknown type letter %s" % (key,)))
 
+def unpack_typecode(space, w_typecode):
+    if space.is_true(space.isinstance(w_typecode, space.w_str)):
+        letter = space.str_w(w_typecode)
+        return letter2tp(space, letter)
+    else:
+        w_size, w_align = space.unpacktuple(w_typecode, expected_length=2)
+        return ('V', space.int_w(w_size), space.int_w(w_align)) # value object
+
 def _get_type_(space, key):
     try:
         return TYPEMAP[key]
@@ -100,6 +108,13 @@
         self.w_cache = space.newdict()
         self.space = space
 
+    def get_arg_type(self, letter, argsize, argalignment):
+        space = self.space
+        if letter == 'V': # xxx leaks
+            return make_struct_ffitype(argsize, argalignment)
+        else:
+            return _get_type_(space, letter)
+
     def get_type(self, key):
         space = self.space
         return _get_type_(space, key)
@@ -125,8 +140,10 @@
             else:
                 raise
         argtypes_w = space.unpackiterable(w_argtypes)
-        argtypes = [space.str_w(w_arg) for w_arg in argtypes_w]
-        ffi_argtypes = [self.get_type(arg) for arg in argtypes]
+        argtypes = [unpack_typecode(space, w_arg) for w_arg in argtypes_w]
+        ffi_argtypes = [self.get_arg_type(letter, argsize, argalignment)
+                                               for letter, argsize, argalignment
+                                                    in argtypes]
         try:
             ptr = self.cdll.getrawpointer(name, ffi_argtypes, ffi_restype)
             w_funcptr = W_FuncPtr(space, ptr, argtypes, restype)
@@ -180,14 +197,6 @@
     w_exception = space.getattr(w_mod, space.wrap("SegfaultException"))
     return OperationError(w_exception, space.wrap(reason))
 
-def unpack_typecode(space, w_typecode):
-    if space.is_true(space.isinstance(w_typecode, space.w_str)):
-        letter = space.str_w(w_typecode)
-        return letter2tp(space, letter)
-    else:
-        w_size, w_align = space.unpacktuple(w_typecode, expected_length=2)
-        return ('?', space.int_w(w_size), space.int_w(w_align))
-
 
 class W_DataInstance(Wrappable):
     def __init__(self, space, size, address=r_uint(0)):
@@ -308,6 +317,7 @@
 
     def call(self, space, args_w):
         from pypy.module._rawffi.array import W_ArrayInstance
+        from pypy.module._rawffi.structure import W_StructureInstance
         argnum = len(args_w)
         if argnum != len(self.argtypes):
             msg = "Wrong number of argument: expected %d, got %d" % (
@@ -315,20 +325,31 @@
             raise OperationError(space.w_TypeError, space.wrap(msg))
         args_ll = []
         for i in range(argnum):
-            argtype = self.argtypes[i]
+            argtype_letter, argtype_size, argtype_alignment = self.argtypes[i]
             w_arg = args_w[i]
-            arg = space.interp_w(W_ArrayInstance, w_arg)
-            if arg.length != 1:
-                msg = ("Argument %d should be an array of length 1, "
-                       "got length %d" % (i+1, arg.length))
-                raise OperationError(space.w_TypeError, space.wrap(msg))
-            letter = arg.shape.itemtp[0]
-            if letter != argtype:
-                if not (argtype in TYPEMAP_PTR_LETTERS and
-                        letter in TYPEMAP_PTR_LETTERS):
-                    msg = "Argument %d should be typecode %s, got %s" % (
-                        i+1, argtype, letter)
+            if argtype_letter == 'V': # by value object
+                arg = space.interp_w(W_StructureInstance, w_arg)
+                if (arg.shape.size != argtype_size or
+                    arg.shape.alignment != argtype_alignment):
+                    msg = ("Argument %d should be a structure of size %d and "
+                           "alignment %d, "
+                           "got instead size %d and alignment %d" %
+                           (i+1, argtype_size, argtype_alignment,
+                            arg.shape.size, arg.shape.alignment))
+                    raise OperationError(space.w_TypeError, space.wrap(msg))
+            else:
+                arg = space.interp_w(W_ArrayInstance, w_arg)
+                if arg.length != 1:
+                    msg = ("Argument %d should be an array of length 1, "
+                           "got length %d" % (i+1, arg.length))
                     raise OperationError(space.w_TypeError, space.wrap(msg))
+                letter = arg.shape.itemtp[0]
+                if letter != argtype_letter:
+                    if not (argtype_letter in TYPEMAP_PTR_LETTERS and
+                            letter in TYPEMAP_PTR_LETTERS):
+                        msg = "Argument %d should be typecode %s, got %s" % (
+                            i+1, argtype_letter, letter)
+                        raise OperationError(space.w_TypeError, space.wrap(msg))
             args_ll.append(arg.ll_buffer)
             # XXX we could avoid the intermediate list args_ll
         if self.resarray is not None:

Modified: pypy/dist/pypy/module/_rawffi/test/test__rawffi.py
==============================================================================
--- pypy/dist/pypy/module/_rawffi/test/test__rawffi.py	(original)
+++ pypy/dist/pypy/module/_rawffi/test/test__rawffi.py	Fri Feb 22 15:57:21 2008
@@ -112,6 +112,15 @@
             return callback();
         }
 
+        struct x_y {
+            long x;
+            long y;
+        };
+
+        long sum_x_y(struct x_y s) {
+            return s.x + s.y;
+        }
+        
         '''))
         return compile_c_module([c_file], 'x', ExternalCompilationInfo())
     prepare_c_example = staticmethod(prepare_c_example)
@@ -498,7 +507,7 @@
         s = struct.calcsize("i")
         assert (repr(_rawffi.Array('i')) ==
                 "<_rawffi.Array 'i' (%d, %d)>" % (s, s))
-        assert repr(_rawffi.Array((18, 2))) == "<_rawffi.Array '?' (18, 2)>"
+        assert repr(_rawffi.Array((18, 2))) == "<_rawffi.Array 'V' (18, 2)>"
         assert (repr(_rawffi.Structure([('x', 'i'), ('yz', 'i')])) ==
                 "<_rawffi.Structure 'x' 'yz' (%d, %d)>" % (2*s, s))
 
@@ -612,6 +621,18 @@
         raises(_rawffi.SegfaultException, a.__getitem__, 3)
         raises(_rawffi.SegfaultException, a.__setitem__, 3, 3)
 
+    def test_struct_byvalue(self):
+        import _rawffi
+        X_Y = _rawffi.Structure([('x', 'l'), ('y', 'l')])
+        x_y = X_Y()
+        lib = _rawffi.CDLL(self.lib_name)
+        sum_x_y = lib.ptr('sum_x_y', [X_Y.gettypecode()], 'l')
+        x_y.x = 200
+        x_y.y = 220
+        res = sum_x_y(x_y)
+        assert res[0] == 420
+        x_y.free()
+
 
 class AppTestAutoFree:
     def setup_class(cls):

Modified: pypy/dist/pypy/rlib/libffi.py
==============================================================================
--- pypy/dist/pypy/rlib/libffi.py	(original)
+++ pypy/dist/pypy/rlib/libffi.py	Fri Feb 22 15:57:21 2008
@@ -40,6 +40,8 @@
     FFI_BAD_TYPEDEF = rffi_platform.ConstantInteger('FFI_BAD_TYPEDEF')
     FFI_DEFAULT_ABI = rffi_platform.ConstantInteger('FFI_DEFAULT_ABI')
 
+    FFI_TYPE_STRUCT = rffi_platform.ConstantInteger('FFI_TYPE_STRUCT')
+
     size_t = rffi_platform.SimpleType("size_t", rffi.ULONG)
 
     ffi_type = rffi_platform.Struct('ffi_type', [('size', rffi.ULONG),
@@ -113,6 +115,7 @@
 FFI_OK = cConfig.FFI_OK
 FFI_BAD_TYPEDEF = cConfig.FFI_BAD_TYPEDEF
 FFI_DEFAULT_ABI = rffi.cast(rffi.USHORT, cConfig.FFI_DEFAULT_ABI)
+FFI_TYPE_STRUCT = rffi.cast(rffi.USHORT, cConfig.FFI_TYPE_STRUCT)
 FFI_CIFP = rffi.COpaquePtr('ffi_cif', compilation_info=CConfig.
                            _compilation_info_)
 
@@ -161,6 +164,14 @@
     # XXX rffi.cast here...
     return res
 
+def make_struct_ffitype(size, aligment):
+    tp = lltype.malloc(FFI_TYPE_P.TO, flavor='raw')
+    tp.c_type = FFI_TYPE_STRUCT
+    tp.c_size = rffi.cast(rffi.SIZE_T, size)
+    tp.c_alignment = rffi.cast(rffi.USHORT, aligment)
+    tp.c_elements = lltype.nullptr(FFI_TYPE_PP.TO)
+    return tp
+
 def cast_type_to_ffitype(tp):
     """ This function returns ffi representation of rpython type tp
     """

Modified: pypy/dist/pypy/rlib/test/test_libffi.py
==============================================================================
--- pypy/dist/pypy/rlib/test/test_libffi.py	(original)
+++ pypy/dist/pypy/rlib/test/test_libffi.py	Fri Feb 22 15:57:21 2008
@@ -175,3 +175,59 @@
         del pow
         del libm
         assert not ALLOCATED
+
+    def test_make_struct_fftiype(self):
+        tp = make_struct_ffitype(6, 2)
+        assert tp.c_type == FFI_TYPE_STRUCT
+        assert tp.c_size == 6
+        assert tp.c_alignment == 2
+        lltype.free(tp, flavor='raw')
+
+    def test_struct_by_val(self):
+        from pypy.translator.tool.cbuild import compile_c_module, \
+             ExternalCompilationInfo
+        from pypy.tool.udir import udir
+
+        c_file = udir.ensure("test_libffi", dir=1).join("xlib.c")
+        c_file.write(py.code.Source('''
+        #include <stdlib.h>
+        #include <stdio.h>
+
+        struct x_y {
+            long x;
+            long y;
+        };
+
+        long sum_x_y(struct x_y s) {
+            return s.x + s.y;
+        }
+
+        long sum_x_y_p(struct x_y *p) {
+            return p->x + p->y;
+        }
+        
+        '''))
+        lib_name = compile_c_module([c_file], 'x', ExternalCompilationInfo())
+
+        lib = CDLL(lib_name)
+
+        size = ffi_type_slong.c_size*2
+        alignment = ffi_type_slong.c_alignment
+        tp = make_struct_ffitype(size, alignment)
+
+        sum_x_y = lib.getrawpointer('sum_x_y', [tp], ffi_type_slong)
+
+        buffer = lltype.malloc(rffi.LONGP.TO, 3, flavor='raw')
+        buffer[0] = 200
+        buffer[1] = 220
+        buffer[2] = 666
+        sum_x_y.call([rffi.cast(rffi.VOIDP, buffer)],
+                     rffi.cast(rffi.VOIDP, rffi.ptradd(buffer, 2)))
+        assert buffer[2] == 420
+
+        lltype.free(buffer, flavor='raw')
+        del sum_x_y
+        lltype.free(tp, flavor='raw')
+        del lib
+
+        assert not ALLOCATED



More information about the Pypy-commit mailing list