[pypy-commit] pypy cffi-1.0: A large amount of efforts in a refactoring for two extra lines of test
arigo
noreply at buildbot.pypy.org
Sat May 9 23:23:01 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r77266:29f15f64bf2f
Date: 2015-05-09 23:22 +0200
http://bitbucket.org/pypy/pypy/changeset/29f15f64bf2f/
Log: A large amount of efforts in a refactoring for two extra lines of
test
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
@@ -158,26 +158,35 @@
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
+ # trampoline functions for PyPy.
if self._nostruct_ctfuncptr[0] is None:
fargs, fret, ellipsis = self._unpack(ffi)
- locs = []
+ # 'locs' will be a string of the same length as the final fargs,
+ # containing 'A' where a struct argument was detected, and 'R'
+ # in first position if a struct return value was detected
+ locs = ['\x00'] * len(fargs)
for i in range(len(fargs)):
farg = fargs[i]
if isinstance(farg, ctypestruct.W_CTypeStructOrUnion):
farg = newtype.new_pointer_type(ffi.space, farg)
fargs[i] = farg
- locs.append(i)
+ locs[i] = 'A'
if isinstance(fret, ctypestruct.W_CTypeStructOrUnion):
fret = newtype.new_pointer_type(ffi.space, fret)
fargs = [fret] + fargs
+ locs = ['R'] + locs
fret = newtype.new_void_type(ffi.space)
- locs.append(-1)
ctfuncptr = newtype._new_function_type(
ffi.space, fargs, fret, ellipsis)
- if not locs:
+ if locs == ['\x00'] * len(locs):
locs = None
else:
- locs = locs[:]
+ locs = ''.join(locs)
self._nostruct_ctfuncptr = (ctfuncptr, locs)
return self._nostruct_ctfuncptr
diff --git a/pypy/module/_cffi_backend/structwrapper.py b/pypy/module/_cffi_backend/structwrapper.py
--- a/pypy/module/_cffi_backend/structwrapper.py
+++ b/pypy/module/_cffi_backend/structwrapper.py
@@ -1,13 +1,11 @@
from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter.error import oefmt
from pypy.interpreter.typedef import TypeDef
from pypy.interpreter.gateway import interp2app
-from rpython.rlib.objectmodel import keepalive_until_here
+from rpython.rlib import jit
-from pypy.module._cffi_backend.cdataobj import W_CData
from pypy.module._cffi_backend.cdataobj import W_CDataPtrToStructOrUnion
+from pypy.module._cffi_backend.ctypefunc import W_CTypeFunc
from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
-from pypy.module._cffi_backend.ctypefunc import W_CTypeFunc
class W_StructWrapper(W_Root):
@@ -22,62 +20,62 @@
_immutable_ = True
def __init__(self, w_cdata, locs, rawfunctype):
+ space = w_cdata.space
ctype = w_cdata.ctype
assert isinstance(ctype, W_CTypeFunc)
- self.ctype = ctype # this type takes pointers
+ assert len(ctype.fargs) == len(locs)
+ #
+ self.space = space
self.w_cdata = w_cdata
- if locs[-1] == -1: # return value is a struct/union
- locs = locs[:-1]
- self.ctresptrtype = ctype.fargs[0]
- else:
- self.ctresptrtype = None
self.locs = locs
+ self.fargs = ctype.fargs
self.rawfunctype = rawfunctype
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
+ space = self.space
+ locs = self.locs
+ result_w = args_w[:]
+ for i in range(start_index, min(len(args_w), len(locs))):
+ if locs[i] != 'A':
+ continue
+ w_arg = args_w[i]
+ farg = self.fargs[i] # <ptr to struct/union>
+ if (isinstance(w_arg, W_CTypeStructOrUnion) and
+ w_arg.ctype is farg.ctitem):
+ # fast way: just make a new W_CData of ctype "ptr to struct"
+ # which points to the same raw memory as the existing W_CData
+ # of ctype "struct"
+ w_arg = W_CData(space, w_arg.unsafe_escaping_ptr(), farg)
+ else:
+ # slow way: build a new "ptr to struct" W_CData by calling
+ # the equivalenet of ffi.new()
+ if space.is_w(w_arg, space.w_None):
+ continue
+ w_arg = farg.newp(w_arg)
+ result_w[i] = w_arg
+ return result_w
+
def descr_call(self, args_w):
- space = self.w_cdata.space
- ctype = self.ctype
- shift = (self.ctresptrtype is not None)
- expected_num_args = len(ctype.fargs) - shift
- if len(args_w) != expected_num_args:
- raise oefmt(space.w_TypeError,
- "'%s' expects %d arguments, got %d",
- ctype.name, expected_num_args, len(args_w))
-
- # Fix the arguments that are so far "struct/union" and that need
- # to be "ptr to struct/union"
- original_args_w = args_w
- if len(self.locs) > 0:
- args_w = args_w[:]
- for loc in self.locs:
- w_arg = args_w[loc]
- if (not isinstance(w_arg, W_CData) or
- not isinstance(w_arg.ctype, W_CTypeStructOrUnion)):
- raise oefmt(space.w_TypeError,
- "wrong type for argument %d", loc)
- w_arg = W_CData(space, w_arg.unsafe_escaping_ptr(),
- self.ctype.fargs[loc + shift])
- args_w[loc] = w_arg
-
# 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.ctresptrtype is not None:
- w_result_cdata = self.ctresptrtype.newp(space.w_None)
- self.w_cdata.call([w_result_cdata] + args_w)
+ # a first argument.
+ if self.locs[0] == 'R':
+ w_result_cdata = self.fargs[0].newp(self.space.w_None)
+ args_w = [w_result_cdata] + args_w
+ self.w_cdata.call(self._prepare(args_w, 1))
assert isinstance(w_result_cdata, W_CDataPtrToStructOrUnion)
- w_result = w_result_cdata.structobj
+ return w_result_cdata.structobj
else:
- w_result = self.w_cdata.call(args_w)
- keepalive_until_here(original_args_w)
- return w_result
+ return self.w_cdata.call(self._prepare(args_w, 0))
W_StructWrapper.typedef = TypeDef(
- 'FFIStructWrapper',
+ 'FFIFuncStructWrapper',
__call__ = interp2app(W_StructWrapper.descr_call),
)
W_StructWrapper.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -646,3 +646,5 @@
assert s.x == 42
assert ffi.typeof(lib.f) == ffi.typeof(
"struct foo_s(*)(int, struct bar_s)")
+ s = lib.f(14, {'y': -3})
+ assert s.x == -42
More information about the pypy-commit
mailing list