Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r78248:53cddb11ed7c Date: 2015-06-23 09:25 +0200 http://bitbucket.org/pypy/pypy/changeset/53cddb11ed7c/
Log: Mostly no-op reorganization. It avoids promoting the whole W_FunctionWrapper instance, and instead promotes only its rawfunctype attribute. diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py --- a/pypy/module/_cffi_backend/lib_obj.py +++ b/pypy/module/_cffi_backend/lib_obj.py @@ -60,12 +60,12 @@ self.ffi, self.ctx.c_types, getarg(g.c_type_op)) assert isinstance(rawfunctype, realize_c_type.W_RawFuncType) # - w_ct, locs = rawfunctype.unwrap_as_nostruct_fnptr(self.ffi) + rawfunctype.prepare_nostruct_fnptr(self.ffi) # ptr = rffi.cast(rffi.CCHARP, g.c_address) assert ptr - return W_FunctionWrapper(self.space, ptr, g.c_size_or_direct_fn, w_ct, - locs, rawfunctype, fnname, self.libname) + return W_FunctionWrapper(self.space, ptr, g.c_size_or_direct_fn, + rawfunctype, fnname, self.libname) @jit.elidable_promote() def _get_attr_elidable(self, attr): @@ -237,7 +237,8 @@ if isinstance(w_value, W_FunctionWrapper): # '&func' returns a regular cdata pointer-to-function if w_value.directfnptr: - return W_CData(space, w_value.directfnptr, w_value.ctype) + ctype = w_value.rawfunctype.nostruct_ctype + return W_CData(space, w_value.directfnptr, ctype) else: return w_value # backward compatibility # diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py --- a/pypy/module/_cffi_backend/realize_c_type.py +++ b/pypy/module/_cffi_backend/realize_c_type.py @@ -1,4 +1,5 @@ import sys +from rpython.rlib import jit from rpython.rlib.rarithmetic import intmask from rpython.rlib.objectmodel import specialize from rpython.rtyper.lltypesystem import lltype, rffi @@ -135,8 +136,12 @@ class W_RawFuncType(W_Root): """Temporary: represents a C function type (not a function pointer)""" + + _immutable_fields_ = ['nostruct_ctype', 'nostruct_locs', 'nostruct_nargs'] _ctfuncptr = None - _nostruct_ctfuncptr = (None, None) + nostruct_ctype = None + nostruct_locs = None + nostruct_nargs = 0 def __init__(self, opcodes, base_index): self.opcodes = opcodes @@ -168,14 +173,16 @@ assert self._ctfuncptr is not None return self._ctfuncptr - def unwrap_as_nostruct_fnptr(self, ffi): - # tweaked version: instead of returning the ctfuncptr corresponding - # exactly to the OP_FUNCTION ... OP_FUNCTION_END opcodes, return - # another one in which the struct args are replaced with ptr-to- - # struct, and a struct return value is replaced with a hidden first - # arg of type ptr-to-struct. This is how recompiler.py produces + @jit.dont_look_inside + def prepare_nostruct_fnptr(self, ffi): + # tweaked version: instead of returning the ctfuncptr + # corresponding exactly to the OP_FUNCTION ... OP_FUNCTION_END + # opcodes, this builds in self.nostruct_ctype another one in + # which the struct args are replaced with ptr-to- struct, and + # a struct return value is replaced with a hidden first arg of + # type ptr-to-struct. This is how recompiler.py produces # trampoline functions for PyPy. - if self._nostruct_ctfuncptr[0] is None: + if self.nostruct_ctype is None: fargs, fret, ellipsis = self._unpack(ffi) # 'locs' will be a string of the same length as the final fargs, # containing 'A' where a struct argument was detected, and 'R' @@ -198,8 +205,10 @@ locs = None else: locs = ''.join(locs) - self._nostruct_ctfuncptr = (ctfuncptr, locs) - return self._nostruct_ctfuncptr + self.nostruct_ctype = ctfuncptr + self.nostruct_locs = locs + self.nostruct_nargs = len(ctfuncptr.fargs) - (locs is not None and + locs[0] == 'R') def unexpected_fn_type(self, ffi): fargs, fret, ellipsis = self._unpack(ffi) diff --git a/pypy/module/_cffi_backend/wrapper.py b/pypy/module/_cffi_backend/wrapper.py --- a/pypy/module/_cffi_backend/wrapper.py +++ b/pypy/module/_cffi_backend/wrapper.py @@ -25,8 +25,14 @@ _immutable_ = True common_doc_str = 'direct call to the C function of the same name' - def __init__(self, space, fnptr, directfnptr, ctype, - locs, rawfunctype, fnname, modulename): + def __init__(self, space, fnptr, directfnptr, + rawfunctype, fnname, modulename): + # everything related to the type of the function is accessed + # as immutable attributes of the 'rawfunctype' object, which + # is a W_RawFuncType. This gives us an obvious thing to + # promote in order to do the call. + ctype = rawfunctype.nostruct_ctype + locs = rawfunctype.nostruct_locs assert isinstance(ctype, W_CTypeFunc) assert ctype.cif_descr is not None # not for '...' functions assert locs is None or len(ctype.fargs) == len(locs) @@ -34,84 +40,86 @@ self.space = space self.fnptr = fnptr self.directfnptr = directfnptr - self.ctype = ctype - self.locs = locs self.rawfunctype = rawfunctype self.fnname = fnname self.modulename = modulename - self.nargs_expected = len(ctype.fargs) - (locs is not None and - locs[0] == 'R') def typeof(self, ffi): return self.rawfunctype.unwrap_as_fnptr(ffi) - @jit.unroll_safe - def _prepare(self, args_w, start_index): - # replaces struct/union arguments with ptr-to-struct/union arguments + def descr_call(self, args_w): space = self.space - locs = self.locs - fargs = self.ctype.fargs - for i in range(start_index, len(locs)): - if locs[i] != 'A': - continue - w_arg = args_w[i] - farg = fargs[i] # <ptr to struct/union> - assert isinstance(farg, W_CTypePtrOrArray) - if isinstance(w_arg, W_CData) and w_arg.ctype is farg.ctitem: - # fast way: we are given a W_CData "struct", so just make - # a new W_CData "ptr-to-struct" which points to the same - # raw memory. We use unsafe_escaping_ptr(), so we have to - # make sure the original 'w_arg' stays alive; the easiest - # is to build an instance of W_CDataPtrToStructOrUnion. - w_arg = W_CDataPtrToStructOrUnion( - space, w_arg.unsafe_escaping_ptr(), farg, w_arg) - else: - # slow way: build a new "ptr to struct" W_CData by calling - # the equivalent of ffi.new() - if space.is_w(w_arg, space.w_None): - continue - w_arg = farg.newp(w_arg) - args_w[i] = w_arg - - def descr_call(self, args_w): - self = jit.promote(self) - if len(args_w) != self.nargs_expected: - space = self.space - if self.nargs_expected == 0: + rawfunctype = jit.promote(self.rawfunctype) + ctype = rawfunctype.nostruct_ctype + locs = rawfunctype.nostruct_locs + nargs_expected = rawfunctype.nostruct_nargs + # + if len(args_w) != nargs_expected: + if nargs_expected == 0: raise oefmt(space.w_TypeError, "%s() takes no arguments (%d given)", self.fnname, len(args_w)) - elif self.nargs_expected == 1: + elif nargs_expected == 1: raise oefmt(space.w_TypeError, "%s() takes exactly one argument (%d given)", self.fnname, len(args_w)) else: raise oefmt(space.w_TypeError, "%s() takes exactly %d arguments (%d given)", - self.fnname, self.nargs_expected, len(args_w)) + self.fnname, nargs_expected, len(args_w)) # - if self.locs is not None: + if locs is not None: # This case is if there are structs as arguments or return values. # If the result we want to present to the user is "returns struct", # then internally allocate the struct and pass a pointer to it as # a first argument. - if self.locs[0] == 'R': - w_result_cdata = self.ctype.fargs[0].newp(self.space.w_None) + if locs[0] == 'R': + w_result_cdata = ctype.fargs[0].newp(space.w_None) args_w = [w_result_cdata] + args_w - self._prepare(args_w, 1) - self.ctype._call(self.fnptr, args_w) # returns w_None + prepare_args(space, rawfunctype, args_w, 1) + # + ctype._call(self.fnptr, args_w) # returns w_None + # assert isinstance(w_result_cdata, W_CDataPtrToStructOrUnion) return w_result_cdata.structobj else: args_w = args_w[:] - self._prepare(args_w, 0) + prepare_args(space, rawfunctype, args_w, 0) # - return self.ctype._call(self.fnptr, args_w) + return ctype._call(self.fnptr, args_w) def descr_repr(self, space): return space.wrap("<FFIFunctionWrapper for %s()>" % (self.fnname,)) +@jit.unroll_safe +def prepare_args(space, rawfunctype, args_w, start_index): + # replaces struct/union arguments with ptr-to-struct/union arguments + locs = rawfunctype.nostruct_locs + fargs = rawfunctype.nostruct_ctype.fargs + for i in range(start_index, len(locs)): + if locs[i] != 'A': + continue + w_arg = args_w[i] + farg = fargs[i] # <ptr to struct/union> + assert isinstance(farg, W_CTypePtrOrArray) + if isinstance(w_arg, W_CData) and w_arg.ctype is farg.ctitem: + # fast way: we are given a W_CData "struct", so just make + # a new W_CData "ptr-to-struct" which points to the same + # raw memory. We use unsafe_escaping_ptr(), so we have to + # make sure the original 'w_arg' stays alive; the easiest + # is to build an instance of W_CDataPtrToStructOrUnion. + w_arg = W_CDataPtrToStructOrUnion( + space, w_arg.unsafe_escaping_ptr(), farg, w_arg) + else: + # slow way: build a new "ptr to struct" W_CData by calling + # the equivalent of ffi.new() + if space.is_w(w_arg, space.w_None): + continue + w_arg = farg.newp(w_arg) + args_w[i] = w_arg + + W_FunctionWrapper.typedef = TypeDef( 'FFIFunctionWrapper', __repr__ = interp2app(W_FunctionWrapper.descr_repr), _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit