Author: Antonio Cuni <anto.c...@gmail.com> 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 pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit