[pypy-svn] r51900 - in pypy/dist/pypy: lib/_ctypes lib/app_test/ctypes module/_rawffi module/_rawffi/test rlib/test
pedronis at codespeak.net
pedronis at codespeak.net
Wed Feb 27 14:38:36 CET 2008
Author: pedronis
Date: Wed Feb 27 14:38:34 2008
New Revision: 51900
Modified:
pypy/dist/pypy/lib/_ctypes/array.py
pypy/dist/pypy/lib/_ctypes/basics.py
pypy/dist/pypy/lib/_ctypes/function.py
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/array.py
pypy/dist/pypy/module/_rawffi/interp_rawffi.py
pypy/dist/pypy/module/_rawffi/structure.py
pypy/dist/pypy/module/_rawffi/test/test__rawffi.py
pypy/dist/pypy/rlib/test/test_libffi.py
Log:
Support for functions returning structure values.
Now though the mess gettypecode/get_ffi_type/get_arg_type... needs to be refactored and cleaned up.
See the new xxxs.
Modified: pypy/dist/pypy/lib/_ctypes/array.py
==============================================================================
--- pypy/dist/pypy/lib/_ctypes/array.py (original)
+++ pypy/dist/pypy/lib/_ctypes/array.py Wed Feb 27 14:38:34 2008
@@ -85,6 +85,9 @@
res._index = index
return res.__ctypes_from_outparam__()
+ def _CData_retval(self, resbuffer):
+ raise NotImplementedError
+
def _CData_value(self, value):
# array accepts very strange parameters as part of structure
# or function argument...
Modified: pypy/dist/pypy/lib/_ctypes/basics.py
==============================================================================
--- pypy/dist/pypy/lib/_ctypes/basics.py (original)
+++ pypy/dist/pypy/lib/_ctypes/basics.py Wed Feb 27 14:38:34 2008
@@ -47,19 +47,22 @@
# interested only in value anyway
return cobj._get_buffer_value()
- def _CData_output(self, resarray, base=None, index=-1, needs_free=False):
- assert isinstance(resarray, _rawffi.ArrayInstance)
+ def _CData_output(self, resbuffer, base=None, index=-1, needs_free=False):
+ assert isinstance(resbuffer, _rawffi.ArrayInstance)
"""Used when data exits ctypes and goes into user code.
- 'resarray' is a _rawffi array of length 1 containing the value,
+ 'resbuffer' is a _rawffi array of length 1 containing the value,
and this returns a general Python object that corresponds.
"""
res = self.__new__(self)
- res.__dict__['_buffer'] = resarray
+ res.__dict__['_buffer'] = resbuffer
res.__dict__['_base'] = base
res.__dict__['_index'] = index
res.__dict__['_needs_free'] = needs_free
return res.__ctypes_from_outparam__()
+ def _CData_retval(self, resbuffer):
+ return self._CData_output(resbuffer, needs_free=True)
+
def __mul__(self, other):
from _ctypes.array import create_array_type
return create_array_type(self, other)
Modified: pypy/dist/pypy/lib/_ctypes/function.py
==============================================================================
--- pypy/dist/pypy/lib/_ctypes/function.py (original)
+++ pypy/dist/pypy/lib/_ctypes/function.py Wed Feb 27 14:38:34 2008
@@ -80,18 +80,22 @@
restype = self._restype_
funcptr = self._getfuncptr(argtypes, restype)
args = self._wrap_args(argtypes, args)
- resarray = funcptr(*[arg._buffer for obj, arg in args])
+ resbuffer = funcptr(*[arg._buffer for obj, arg in args])
if restype is not None:
- return restype._CData_output(resarray, needs_free=True)
+ return restype._CData_retval(resbuffer)
else:
- resarray.free()
+ resbuffer.free()
def _getfuncptr(self, argtypes, restype):
if restype is None:
import ctypes
restype = ctypes.c_int
argshapes = [arg._ffiargshape for arg in argtypes]
- return self.dll._handle.ptr(self.name, argshapes, restype._ffiletter)
+ if isinstance(restype._ffiargshape, str): # xxx refactor
+ resshape = restype._ffiargshape
+ else:
+ resshape = restype._ffistruct
+ return self.dll._handle.ptr(self.name, argshapes, resshape)
def _guess_argtypes(self, args):
from _ctypes import _CData
Modified: pypy/dist/pypy/lib/_ctypes/structure.py
==============================================================================
--- pypy/dist/pypy/lib/_ctypes/structure.py (original)
+++ pypy/dist/pypy/lib/_ctypes/structure.py Wed Feb 27 14:38:34 2008
@@ -155,6 +155,14 @@
res.__dict__['_base'] = base
res.__dict__['_index'] = index
return res.__ctypes_from_outparam__()
+
+ def _CData_retval(self, resbuffer):
+ res = self.__new__(self)
+ res.__dict__['_buffer'] = resbuffer
+ res.__dict__['_base'] = None
+ res.__dict__['_index'] = -1
+ res.__dict__['_needs_free'] = True
+ return res.__ctypes_from_outparam__()
class Structure(_CData):
__metaclass__ = StructureMeta
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 Wed Feb 27 14:38:34 2008
@@ -164,7 +164,6 @@
assert got == expected
def test_struct_return_2H(self):
- py.test.skip("Structure by value")
class S2H(Structure):
_fields_ = [("x", c_short),
("y", c_short)]
@@ -175,7 +174,6 @@
assert (s2h.x, s2h.y) == (99*2, 88*3)
def test_struct_return_8H(self):
- py.test.skip("Structure by value")
class S8I(Structure):
_fields_ = [("a", c_int),
("b", c_int),
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 Wed Feb 27 14:38:34 2008
@@ -330,7 +330,6 @@
assert got == expected
def test_struct_return_2H(self):
- py.test.skip("Raw structure return")
class S2H(Structure):
_fields_ = [("x", c_short),
("y", c_short)]
@@ -352,7 +351,6 @@
assert (s2h.x, s2h.y) == (99*2, 88*3)
def test_struct_return_8H(self):
- py.test.skip("Raw structure return")
class S8I(Structure):
_fields_ = [("a", c_int),
("b", c_int),
Modified: pypy/dist/pypy/module/_rawffi/array.py
==============================================================================
--- pypy/dist/pypy/module/_rawffi/array.py (original)
+++ pypy/dist/pypy/module/_rawffi/array.py Wed Feb 27 14:38:34 2008
@@ -10,7 +10,7 @@
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.interpreter.error import OperationError, wrap_oserror
from pypy.module._rawffi.interp_rawffi import segfault_exception
-from pypy.module._rawffi.interp_rawffi import W_DataInstance
+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 unpack_typecode, letter2tp
from pypy.rlib.rarithmetic import intmask, r_uint
@@ -26,7 +26,7 @@
return ll_array[pos]
get_elem._annspecialcase_ = 'specialize:arg(2)'
-class W_Array(Wrappable):
+class W_Array(W_DataShape):
def __init__(self, space, itemtp):
assert isinstance(itemtp, tuple)
self.space = space
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 Wed Feb 27 14:38:34 2008
@@ -108,6 +108,7 @@
self.w_cache = space.newdict()
self.space = space
+ # xxx refactor away !
def get_arg_type(self, letter, argsize, argalignment):
space = self.space
if letter == 'V': # xxx leaks
@@ -123,15 +124,28 @@
""" Get a pointer for function name with provided argtypes
and restype
"""
+ # xxx refactor
if space.is_w(w_restype, space.w_None):
- restype = 'v'
+ resshape = None
ffi_restype = ffi_type_void
+ elif space.is_true(space.isinstance(w_restype, space.w_str)):
+ tp_letter = space.str_w(w_restype)
+ if tp_letter == 'v':
+ resshape = None
+ ffi_restype = ffi_type_void
+ else:
+ from pypy.module._rawffi.array import get_array_cache
+ cache = get_array_cache(space)
+ resshape = cache.get_array_type(letter2tp(space, tp_letter))
+ ffi_restype = self.get_type(tp_letter)
else:
- restype = space.str_w(w_restype)
- ffi_restype = self.get_type(restype)
+ from pypy.module._rawffi.structure import W_Structure
+ resshape = space.interp_w(W_Structure, w_restype)
+ ffi_restype = resshape.get_ffi_type()
+
w = space.wrap
w_argtypes = space.newtuple(space.unpackiterable(w_argtypes))
- w_key = space.newtuple([w(name), w_argtypes, w(restype)])
+ w_key = space.newtuple([w(name), w_argtypes, w(resshape)])
try:
return space.getitem(self.w_cache, w_key)
except OperationError, e:
@@ -146,7 +160,7 @@
in argtypes]
try:
ptr = self.cdll.getrawpointer(name, ffi_argtypes, ffi_restype)
- w_funcptr = W_FuncPtr(space, ptr, argtypes, restype)
+ w_funcptr = W_FuncPtr(space, ptr, argtypes, resshape)
space.setitem(self.w_cache, w_key, w_funcptr)
return w_funcptr
except KeyError:
@@ -187,7 +201,7 @@
where argtype_list is a list of single characters and restype is a single
character. The character meanings are more or less the same as in the struct
module, except that s has trailing \x00 added, while p is considered a raw
-buffer."""
+buffer.""" # xxx fix doc
)
unroll_letters_for_numbers = unrolling_iterable("bBhHiIlLqQ")
@@ -197,6 +211,10 @@
w_exception = space.getattr(w_mod, space.wrap("SegfaultException"))
return OperationError(w_exception, space.wrap(reason))
+class W_DataShape(Wrappable):
+
+ def allocate(self, space, length, autofree=False):
+ raise NotImplementedError
class W_DataInstance(Wrappable):
def __init__(self, space, size, address=r_uint(0)):
@@ -305,14 +323,9 @@
wrap_value._annspecialcase_ = 'specialize:arg(1)'
class W_FuncPtr(Wrappable):
- def __init__(self, space, ptr, argtypes, restype):
- from pypy.module._rawffi.array import get_array_cache
+ def __init__(self, space, ptr, argtypes, resshape):
self.ptr = ptr
- if restype != 'v':
- cache = get_array_cache(space)
- self.resarray = cache.get_array_type(letter2tp(space, restype))
- else:
- self.resarray = None
+ self.resshape = resshape
self.argtypes = argtypes
def call(self, space, args_w):
@@ -352,8 +365,8 @@
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:
- result = self.resarray.allocate(space, 1)
+ if self.resshape is not None:
+ result = self.resshape.allocate(space, 1)
self.ptr.call(args_ll, result.ll_buffer)
return space.wrap(result)
else:
Modified: pypy/dist/pypy/module/_rawffi/structure.py
==============================================================================
--- pypy/dist/pypy/module/_rawffi/structure.py (original)
+++ pypy/dist/pypy/module/_rawffi/structure.py Wed Feb 27 14:38:34 2008
@@ -11,9 +11,10 @@
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.interpreter.error import OperationError, wrap_oserror
from pypy.module._rawffi.interp_rawffi import segfault_exception
-from pypy.module._rawffi.interp_rawffi import W_DataInstance
+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_typecode
+from pypy.rlib import libffi
from pypy.rlib.rarithmetic import intmask, r_uint
def unpack_fields(space, w_fields):
@@ -45,7 +46,7 @@
return size, alignment, pos
-class W_Structure(Wrappable):
+class W_Structure(W_DataShape):
def __init__(self, space, w_fields):
fields = unpack_fields(space, w_fields)
name_to_index = {}
@@ -62,6 +63,12 @@
self.fields = fields
self.name_to_index = name_to_index
+ def allocate(self, space, length, autofree=False):
+ # length is ignored!
+ if autofree:
+ return W_StructureInstanceAutoFree(space, self)
+ return W_StructureInstance(space, self, 0)
+
def getindex(self, space, attr):
try:
return self.name_to_index[attr]
@@ -70,9 +77,7 @@
"C Structure has no attribute %s" % attr))
def descr_call(self, space, autofree=False):
- if autofree:
- return space.wrap(W_StructureInstanceAutoFree(space, self))
- return space.wrap(W_StructureInstance(space, self, 0))
+ return space.wrap(self.allocate(space, 1, autofree))
descr_call.unwrap_spec = ['self', ObjSpace, int]
def descr_repr(self, space):
@@ -96,6 +101,21 @@
space.wrap(self.alignment)])
descr_gettypecode.unwrap_spec = ['self', ObjSpace]
+ # get the corresponding ffi_type
+ ffi_type = lltype.nullptr(libffi.FFI_TYPE_P.TO)
+
+ def get_ffi_type(self):
+ if not self.ffi_type:
+ self.ffi_type = libffi.make_struct_ffitype(self.size,
+ self.alignment)
+ return self.ffi_type
+
+ def __del__(self):
+ if self.ffi_type:
+ lltype.free(self.ffi_type, flavor='raw')
+
+
+
def descr_new_structure(space, w_type, w_fields):
return space.wrap(W_Structure(space, w_fields))
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 Wed Feb 27 14:38:34 2008
@@ -120,6 +120,24 @@
long sum_x_y(struct x_y s) {
return s.x + s.y;
}
+
+ struct s2h {
+ short x;
+ short y;
+ };
+
+ struct s2h give(short x, short y) {
+ struct s2h out;
+ out.x = x;
+ out.y = y;
+ return out;
+ }
+
+ struct s2h perturb(struct s2h inp) {
+ inp.x *= 2;
+ inp.y *= 3;
+ return inp;
+ }
'''))
return compile_c_module([c_file], 'x', ExternalCompilationInfo())
@@ -632,6 +650,40 @@
res = sum_x_y(x_y)
assert res[0] == 420
x_y.free()
+ res.free()
+
+ def test_ret_struct(self):
+ import _rawffi
+ S2H = _rawffi.Structure([('x', 'h'), ('y', 'h')])
+ s2h = S2H()
+ lib = _rawffi.CDLL(self.lib_name)
+ give = lib.ptr('give', ['h', 'h'], S2H)
+ a1 = _rawffi.Array('h')(1)
+ a2 = _rawffi.Array('h')(1)
+ a1[0] = 13
+ a2[0] = 17
+ res = give(a1, a2)
+ assert isinstance(res, _rawffi.StructureInstance)
+ assert res.shape is S2H
+ assert res.x == 13
+ assert res.y == 17
+ res.free()
+ a1.free()
+ a2.free()
+
+ s2h.x = 7
+ s2h.y = 11
+ perturb = lib.ptr('perturb', [S2H.gettypecode()], S2H)
+ res = perturb(s2h)
+ assert isinstance(res, _rawffi.StructureInstance)
+ assert res.shape is S2H
+ assert res.x == 14
+ assert res.y == 33
+ assert s2h.x == 7
+ assert s2h.y == 11
+ res.free()
+
+ s2h.free()
class AppTestAutoFree:
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 Wed Feb 27 14:38:34 2008
@@ -231,3 +231,78 @@
del lib
assert not ALLOCATED
+
+ def test_ret_struct_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 s2h {
+ short x;
+ short y;
+ };
+
+ struct s2h give(short x, short y) {
+ struct s2h out;
+ out.x = x;
+ out.y = y;
+ return out;
+ }
+
+ struct s2h perturb(struct s2h inp) {
+ inp.x *= 2;
+ inp.y *= 3;
+ return inp;
+ }
+
+ '''))
+ lib_name = compile_c_module([c_file], 'x', ExternalCompilationInfo())
+
+ lib = CDLL(lib_name)
+
+ size = ffi_type_sshort.c_size*2
+ alignment = ffi_type_sshort.c_alignment
+ tp = make_struct_ffitype(size, alignment)
+
+ give = lib.getrawpointer('give', [ffi_type_sshort, ffi_type_sshort],
+ tp)
+ inbuffer = lltype.malloc(rffi.SHORTP.TO, 2, flavor='raw')
+ inbuffer[0] = rffi.cast(rffi.SHORT, 40)
+ inbuffer[1] = rffi.cast(rffi.SHORT, 72)
+
+ outbuffer = lltype.malloc(rffi.SHORTP.TO, 2, flavor='raw')
+
+ give.call([rffi.cast(rffi.VOIDP, inbuffer),
+ rffi.cast(rffi.VOIDP, rffi.ptradd(inbuffer, 1))],
+ rffi.cast(rffi.VOIDP, outbuffer))
+
+ assert outbuffer[0] == 40
+ assert outbuffer[1] == 72
+
+ perturb = lib.getrawpointer('perturb', [tp], tp)
+
+ inbuffer[0] = rffi.cast(rffi.SHORT, 7)
+ inbuffer[1] = rffi.cast(rffi.SHORT, 11)
+
+ perturb.call([rffi.cast(rffi.VOIDP, inbuffer)],
+ rffi.cast(rffi.VOIDP, outbuffer))
+
+ assert inbuffer[0] == 7
+ assert inbuffer[1] == 11
+
+ assert outbuffer[0] == 14
+ assert outbuffer[1] == 33
+
+ lltype.free(outbuffer, flavor='raw')
+ lltype.free(inbuffer, flavor='raw')
+ del give
+ del perturb
+ lltype.free(tp, flavor='raw')
+ del lib
+
+ assert not ALLOCATED
More information about the Pypy-commit
mailing list