[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