Author: Antonio Cuni <[email protected]>
Branch: ffistruct
Changeset: r49315:fec3defe7d52
Date: 2011-11-10 19:41 +0100
http://bitbucket.org/pypy/pypy/changeset/fec3defe7d52/
Log: move the logic to wrap the result of a call in WrapDispatcher. Will
write the proper docstrings later, now I have to shutdown the laptop
because we are landing :-)
diff --git a/pypy/module/_ffi/dispatcher.py b/pypy/module/_ffi/dispatcher.py
--- a/pypy/module/_ffi/dispatcher.py
+++ b/pypy/module/_ffi/dispatcher.py
@@ -2,9 +2,10 @@
from pypy.rlib import jit
from pypy.rlib.rarithmetic import intmask, r_uint
from pypy.rpython.lltypesystem import rffi
-from pypy.module._rawffi.structure import W_StructureInstance
+from pypy.module._rawffi.structure import W_StructureInstance, W_Structure
+from pypy.module._ffi.interp_ffitype import app_types
-class AbstractDispatcher(object):
+class UnwrapDispatcher(object):
def __init__(self, space):
self.space = space
@@ -161,3 +162,120 @@
"""
self.error(w_ffitype, w_structinstance)
+
+
+class WrapDispatcher(object):
+
+ def __init__(self, space):
+ self.space = space
+
+ def do_and_wrap(self, w_ffitype):
+ space = self.space
+ if w_ffitype.is_longlong():
+ # note that we must check for longlong first, because either
+ # is_signed or is_unsigned returns true anyway
+ assert libffi.IS_32_BIT
+ return self._longlong(w_ffitype)
+ elif w_ffitype.is_signed():
+ intval = self.get_signed(w_ffitype)
+ return space.wrap(intval)
+ elif w_ffitype is app_types.ulong:
+ # we need to be careful when the return type is ULONG, because the
+ # value might not fit into a signed LONG, and thus might require
+ # and app-evel <long>. This is why we need to treat it separately
+ # than the other unsigned types.
+ uintval = self.get_unsigned(w_ffitype)
+ return space.wrap(uintval)
+ elif w_ffitype.is_unsigned(): # note that ulong is handled just before
+ intval = self.get_unsigned_which_fits_into_a_signed(w_ffitype)
+ return space.wrap(intval)
+ elif w_ffitype.is_pointer():
+ uintval = self.get_pointer(w_ffitype)
+ return space.wrap(uintval)
+ elif w_ffitype.is_char():
+ ucharval = self.get_char(w_ffitype)
+ return space.wrap(chr(ucharval))
+ elif w_ffitype.is_unichar():
+ wcharval = self.get_unichar(w_ffitype)
+ return space.wrap(unichr(wcharval))
+ elif w_ffitype.is_double():
+ return self._float(w_ffitype)
+ elif w_ffitype.is_singlefloat():
+ return self._singlefloat(w_ffitype)
+ elif w_ffitype.is_struct():
+ w_datashape = w_ffitype.w_datashape
+ assert isinstance(w_datashape, W_Structure)
+ uintval = self.get_struct(w_datashape) # this is the ptr to the
struct
+ return w_datashape.fromaddress(space, uintval)
+ elif w_ffitype.is_void():
+ voidval = self.get_void(w_ffitype)
+ assert voidval is None
+ return space.w_None
+ else:
+ assert False, "Return value shape '%s' not supported" % w_ffitype
+
+ def _longlong(self, w_ffitype):
+ # a separate function, which can be seen by the jit or not,
+ # depending on whether longlongs are supported
+ if w_ffitype is app_types.slonglong:
+ longlongval = self.get_longlong(w_ffitype)
+ return self.space.wrap(longlongval)
+ elif w_ffitype is app_types.ulonglong:
+ ulonglongval = self.get_ulonglong(w_ffitype)
+ return self.space.wrap(ulonglongval)
+ else:
+ self.error(w_ffitype)
+
+ def _float(self, w_ffitype):
+ # a separate function, which can be seen by the jit or not,
+ # depending on whether floats are supported
+ floatval = self.get_float(w_ffitype)
+ return self.space.wrap(floatval)
+
+ def _singlefloat(self, w_ffitype):
+ # a separate function, which can be seen by the jit or not,
+ # depending on whether singlefloats are supported
+ singlefloatval = self.get_singlefloat(w_ffitype)
+ return self.space.wrap(float(singlefloatval))
+
+ def error(self, w_ffitype, w_obj):
+ assert False # XXX raise a proper app-level exception
+
+ def get_longlong(self, w_ffitype):
+ self.error(w_ffitype)
+
+ def get_ulonglong(self, w_ffitype):
+ self.error(w_ffitype)
+
+ def get_signed(self, w_ffitype):
+ self.error(w_ffitype)
+
+ def get_unsigned(self, w_ffitype):
+ self.error(w_ffitype)
+
+ def get_unsigned_which_fits_into_a_signed(self, w_ffitype):
+ self.error(w_ffitype)
+
+ def get_pointer(self, w_ffitype):
+ self.error(w_ffitype)
+
+ def get_char(self, w_ffitype):
+ self.error(w_ffitype)
+
+ def get_unichar(self, w_ffitype):
+ self.error(w_ffitype)
+
+ def get_float(self, w_ffitype):
+ self.error(w_ffitype)
+
+ def get_singlefloat(self, w_ffitype):
+ self.error(w_ffitype)
+
+ def get_struct(self, w_datashape):
+ """
+ XXX: write nice docstring in the base class, must return an ULONG
+ """
+ return self.func.call(self.argchain, rffi.ULONG, is_struct=True)
+
+ def get_void(self, w_ffitype):
+ self.error(w_ffitype)
diff --git a/pypy/module/_ffi/interp_funcptr.py
b/pypy/module/_ffi/interp_funcptr.py
--- a/pypy/module/_ffi/interp_funcptr.py
+++ b/pypy/module/_ffi/interp_funcptr.py
@@ -3,7 +3,6 @@
operationerrfmt
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef
-from pypy.module._rawffi.structure import W_StructureInstance, W_Structure
from pypy.module._ffi.interp_ffitype import W_FFIType
#
from pypy.rpython.lltypesystem import lltype, rffi
@@ -13,7 +12,7 @@
from pypy.rlib.rdynload import DLOpenError
from pypy.rlib.rarithmetic import intmask, r_uint
from pypy.rlib.objectmodel import we_are_translated
-from pypy.module._ffi.dispatcher import AbstractDispatcher
+from pypy.module._ffi.dispatcher import UnwrapDispatcher, WrapDispatcher
def unwrap_ffitype(space, w_argtype, allow_void=False):
@@ -49,7 +48,7 @@
self.func.name, expected, arg, given)
#
argchain = libffi.ArgChain()
- argpusher = ArgumentPusherDispatcher(space, argchain, self.to_free)
+ argpusher = PushArgumentDispatcher(space, argchain, self.to_free)
for i in range(expected):
w_argtype = self.argtypes_w[i]
w_arg = args_w[i]
@@ -59,7 +58,9 @@
def call(self, space, args_w):
self = jit.promote(self)
argchain = self.build_argchain(space, args_w)
- return self._do_call(space, argchain)
+ func_caller = CallFunctionDispatcher(space, self.func, argchain)
+ return func_caller.do_and_wrap(self.w_restype)
+ #return self._do_call(space, argchain)
def free_temp_buffers(self, space):
for buf in self.to_free:
@@ -69,122 +70,6 @@
lltype.free(buf, flavor='raw')
self.to_free = []
- def _do_call(self, space, argchain):
- w_restype = self.w_restype
- if w_restype.is_longlong():
- # note that we must check for longlong first, because either
- # is_signed or is_unsigned returns true anyway
- assert libffi.IS_32_BIT
- return self._call_longlong(space, argchain)
- elif w_restype.is_signed():
- return self._call_int(space, argchain)
- elif w_restype.is_unsigned() or w_restype.is_pointer():
- return self._call_uint(space, argchain)
- elif w_restype.is_char():
- intres = self.func.call(argchain, rffi.UCHAR)
- return space.wrap(chr(intres))
- elif w_restype.is_unichar():
- intres = self.func.call(argchain, rffi.WCHAR_T)
- return space.wrap(unichr(intres))
- elif w_restype.is_double():
- return self._call_float(space, argchain)
- elif w_restype.is_singlefloat():
- return self._call_singlefloat(space, argchain)
- elif w_restype.is_struct():
- w_datashape = w_restype.w_datashape
- assert isinstance(w_datashape, W_Structure)
- ptrval = self.func.call(argchain, rffi.ULONG, is_struct=True)
- return w_datashape.fromaddress(space, ptrval)
- elif w_restype.is_void():
- voidres = self.func.call(argchain, lltype.Void)
- assert voidres is None
- return space.w_None
- else:
- assert False, "Return value shape '%s' not supported" % w_restype
-
- def _call_int(self, space, argchain):
- # if the declared return type of the function is smaller than LONG,
- # the result buffer may contains garbage in its higher bits. To get
- # the correct value, and to be sure to handle the signed/unsigned case
- # correctly, we need to cast the result to the correct type. After
- # that, we cast it back to LONG, because this is what we want to pass
- # to space.wrap in order to get a nice applevel <int>.
- #
- restype = self.func.restype
- call = self.func.call
- if restype is libffi.types.slong:
- intres = call(argchain, rffi.LONG)
- elif restype is libffi.types.sint:
- intres = rffi.cast(rffi.LONG, call(argchain, rffi.INT))
- elif restype is libffi.types.sshort:
- intres = rffi.cast(rffi.LONG, call(argchain, rffi.SHORT))
- elif restype is libffi.types.schar:
- intres = rffi.cast(rffi.LONG, call(argchain, rffi.SIGNEDCHAR))
- else:
- raise OperationError(space.w_ValueError,
- space.wrap('Unsupported restype'))
- return space.wrap(intres)
-
- def _call_uint(self, space, argchain):
- # the same comment as above apply. Moreover, we need to be careful
- # when the return type is ULONG, because the value might not fit into
- # a signed LONG: this is the only case in which we cast the result to
- # something different than LONG; as a result, the applevel value will
- # be a <long>.
- #
- # Note that we check for ULONG before UINT: this is needed on 32bit
- # machines, where they are they same: if we checked for UINT before
- # ULONG, we would cast to the wrong type. Note that this also means
- # that on 32bit the UINT case will never be entered (because it is
- # handled by the ULONG case).
- restype = self.func.restype
- call = self.func.call
- if restype is libffi.types.ulong:
- # special case
- uintres = call(argchain, rffi.ULONG)
- return space.wrap(uintres)
- elif restype is libffi.types.pointer:
- ptrres = call(argchain, rffi.VOIDP)
- uintres = rffi.cast(rffi.ULONG, ptrres)
- return space.wrap(uintres)
- elif restype is libffi.types.uint:
- intres = rffi.cast(rffi.LONG, call(argchain, rffi.UINT))
- elif restype is libffi.types.ushort:
- intres = rffi.cast(rffi.LONG, call(argchain, rffi.USHORT))
- elif restype is libffi.types.uchar:
- intres = rffi.cast(rffi.LONG, call(argchain, rffi.UCHAR))
- else:
- raise OperationError(space.w_ValueError,
- space.wrap('Unsupported restype'))
- return space.wrap(intres)
-
- def _call_float(self, space, argchain):
- # a separate function, which can be seen by the jit or not,
- # depending on whether floats are supported
- floatres = self.func.call(argchain, rffi.DOUBLE)
- return space.wrap(floatres)
-
- def _call_longlong(self, space, argchain):
- # a separate function, which can be seen by the jit or not,
- # depending on whether longlongs are supported
- restype = self.func.restype
- call = self.func.call
- if restype is libffi.types.slonglong:
- llres = call(argchain, rffi.LONGLONG)
- return space.wrap(llres)
- elif restype is libffi.types.ulonglong:
- ullres = call(argchain, rffi.ULONGLONG)
- return space.wrap(ullres)
- else:
- raise OperationError(space.w_ValueError,
- space.wrap('Unsupported longlong restype'))
-
- def _call_singlefloat(self, space, argchain):
- # a separate function, which can be seen by the jit or not,
- # depending on whether singlefloats are supported
- sfres = self.func.call(argchain, rffi.FLOAT)
- return space.wrap(float(sfres))
-
def getaddr(self, space):
"""
Return the physical address in memory of the function
@@ -192,14 +77,14 @@
return space.wrap(rffi.cast(rffi.LONG, self.func.funcsym))
-class ArgumentPusherDispatcher(AbstractDispatcher):
+class PushArgumentDispatcher(UnwrapDispatcher):
"""
A dispatcher used by W_FuncPtr to unwrap the app-level objects into
low-level types and push them to the argchain.
"""
def __init__(self, space, argchain, to_free):
- AbstractDispatcher.__init__(self, space)
+ UnwrapDispatcher.__init__(self, space)
self.argchain = argchain
self.to_free = to_free
@@ -244,6 +129,91 @@
self.argchain.arg_raw(ptrval)
+class CallFunctionDispatcher(WrapDispatcher):
+ """
+ A dispatcher used by W_FuncPtr to call the function, expect the result of
+ a correct low-level type and wrap it to the corresponding app-level type
+ """
+
+ def __init__(self, space, func, argchain):
+ WrapDispatcher.__init__(self, space)
+ self.func = func
+ self.argchain = argchain
+
+ def get_longlong(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.LONGLONG)
+
+ def get_ulonglong(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.ULONGLONG)
+
+ def get_signed(self, w_ffitype):
+ # if the declared return type of the function is smaller than LONG,
+ # the result buffer may contains garbage in its higher bits. To get
+ # the correct value, and to be sure to handle the signed/unsigned case
+ # correctly, we need to cast the result to the correct type. After
+ # that, we cast it back to LONG, because this is what we want to pass
+ # to space.wrap in order to get a nice applevel <int>.
+ #
+ restype = w_ffitype.ffitype
+ call = self.func.call
+ if restype is libffi.types.slong:
+ return call(self.argchain, rffi.LONG)
+ elif restype is libffi.types.sint:
+ return rffi.cast(rffi.LONG, call(self.argchain, rffi.INT))
+ elif restype is libffi.types.sshort:
+ return rffi.cast(rffi.LONG, call(self.argchain, rffi.SHORT))
+ elif restype is libffi.types.schar:
+ return rffi.cast(rffi.LONG, call(self.argchain, rffi.SIGNEDCHAR))
+ else:
+ raise OperationError(space.w_ValueError,
+ space.wrap('Unsupported restype'))
+
+ def get_unsigned(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.ULONG)
+
+ def get_unsigned_which_fits_into_a_signed(self, w_ffitype):
+ # the same comment as get_signed apply
+ restype = w_ffitype.ffitype
+ call = self.func.call
+ if restype is libffi.types.uint:
+ assert not libffi.IS_32_BIT
+ # on 32bit machines, we should never get here, because it's a case
+ # which has already been handled by get_unsigned above.
+ return rffi.cast(rffi.LONG, call(self.argchain, rffi.UINT))
+ elif restype is libffi.types.ushort:
+ return rffi.cast(rffi.LONG, call(self.argchain, rffi.USHORT))
+ elif restype is libffi.types.uchar:
+ return rffi.cast(rffi.LONG, call(self.argchain, rffi.UCHAR))
+ else:
+ raise OperationError(space.w_ValueError,
+ space.wrap('Unsupported restype'))
+ return space.wrap(intres)
+
+ def get_pointer(self, w_ffitype):
+ ptrres = self.func.call(self.argchain, rffi.VOIDP)
+ return rffi.cast(rffi.ULONG, ptrres)
+
+ def get_char(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.UCHAR)
+
+ def get_unichar(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.WCHAR_T)
+
+ def get_float(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.DOUBLE)
+
+ def get_singlefloat(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.FLOAT)
+
+ def get_struct(self, w_datashape):
+ """
+ XXX: write nice docstring in the base class, must return an ULONG
+ """
+ return self.func.call(self.argchain, rffi.ULONG, is_struct=True)
+
+ def get_void(self, w_ffitype):
+ return self.func.call(self.argchain, lltype.Void)
+
def unpack_argtypes(space, w_argtypes, w_restype):
argtypes_w = [space.interp_w(W_FFIType, w_argtype)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit