[pypy-commit] pypy ffi-backend: Move things around, creating rlib/jit_libffi.py which can receive

arigo noreply at buildbot.pypy.org
Thu Aug 2 22:42:03 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: ffi-backend
Changeset: r56545:546f3db4f667
Date: 2012-08-02 13:35 +0200
http://bitbucket.org/pypy/pypy/changeset/546f3db4f667/

Log:	Move things around, creating rlib/jit_libffi.py which can receive
	special JIT support.

diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -5,7 +5,10 @@
 import sys
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
-from pypy.rlib import jit, clibffi
+from pypy.rlib import jit, clibffi, jit_libffi
+from pypy.rlib.jit_libffi import CIF_DESCRIPTION, CIF_DESCRIPTION_P
+from pypy.rlib.jit_libffi import FFI_TYPE, FFI_TYPE_P, FFI_TYPE_PP
+from pypy.rlib.jit_libffi import SIZE_OF_FFI_ARG
 from pypy.rlib.objectmodel import we_are_translated, instantiate
 from pypy.rlib.objectmodel import keepalive_until_here
 
@@ -120,42 +123,24 @@
         mustfree_max_plus_1 = 0
         buffer = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
         try:
-            buffer_array = rffi.cast(rffi.VOIDPP, buffer)
             for i in range(len(args_w)):
                 data = rffi.ptradd(buffer, cif_descr.exchange_args[i])
-                buffer_array[i] = data
                 w_obj = args_w[i]
                 argtype = self.fargs[i]
                 if argtype.convert_argument_from_object(data, w_obj):
                     # argtype is a pointer type, and w_obj a list/tuple/str
                     mustfree_max_plus_1 = i + 1
-            resultdata = rffi.ptradd(buffer, cif_descr.exchange_result)
 
             ec = cerrno.get_errno_container(space)
             cerrno.restore_errno_from(ec)
-            clibffi.c_ffi_call(cif_descr.cif,
-                               rffi.cast(rffi.VOIDP, funcaddr),
-                               rffi.cast(rffi.VOIDP, resultdata),
-                               buffer_array)
+            jit_libffi.jit_ffi_call(cif_descr,
+                                    rffi.cast(rffi.VOIDP, funcaddr),
+                                    buffer)
             e = cerrno.get_real_errno()
             cerrno.save_errno_into(ec, e)
 
-            if self.ctitem.is_primitive_integer:
-                if BIG_ENDIAN:
-                    # For results of precisely these types, libffi has a
-                    # strange rule that they will be returned as a whole
-                    # 'ffi_arg' if they are smaller.  The difference
-                    # only matters on big-endian.
-                    if self.ctitem.size < SIZE_OF_FFI_ARG:
-                        diff = SIZE_OF_FFI_ARG - self.ctitem.size
-                        resultdata = rffi.ptradd(resultdata, diff)
-                w_res = self.ctitem.convert_to_object(resultdata)
-            elif isinstance(self.ctitem, W_CTypeVoid):
-                w_res = space.w_None
-            elif isinstance(self.ctitem, W_CTypeStructOrUnion):
-                w_res = self.ctitem.copy_and_convert_to_object(resultdata)
-            else:
-                w_res = self.ctitem.convert_to_object(resultdata)
+            resultdata = rffi.ptradd(buffer, cif_descr.exchange_result)
+            w_res = self.ctitem.copy_and_convert_to_object(resultdata)
         finally:
             for i in range(mustfree_max_plus_1):
                 argtype = self.fargs[i]
@@ -180,46 +165,11 @@
 
 # ____________________________________________________________
 
-# The "cif" is a block of raw memory describing how to do a call via libffi.
-# It starts with a block of memory of type FFI_CIF, which is used by libffi
-# itself.  Following it, we find _cffi_backend-specific information:
-#
-#  - 'exchange_size': an integer that tells how big a buffer we must
-#    allocate for the call; this buffer should start with an array of
-#    pointers to the actual argument values.
-#
-#  - 'exchange_result': the offset in that buffer for the result of the call.
-#
-#  - 'exchange_args[nargs]': the offset in that buffer for each argument.
-#
-# Following this, we have other data structures for libffi (with direct
-# pointers from the FFI_CIF to these data structures):
-#
-#  - the argument types, as an array of 'ffi_type *'.
-#
-#  - optionally, the result's and the arguments' ffi type data
-#    (this is used only for 'struct' ffi types; in other cases the
-#    'ffi_type *' just points to static data like 'ffi_type_sint32').
 
-FFI_CIF = clibffi.FFI_CIFP.TO
-FFI_TYPE = clibffi.FFI_TYPE_P.TO
-FFI_TYPE_P = clibffi.FFI_TYPE_P
-FFI_TYPE_PP = clibffi.FFI_TYPE_PP
-SIZE_OF_FFI_ARG = rffi.sizeof(clibffi.ffi_arg)
+W_CTypeFunc.cif_descr = lltype.nullptr(CIF_DESCRIPTION)     # default value
+
 BIG_ENDIAN = sys.byteorder == 'big'
 
-CIF_DESCRIPTION = lltype.Struct(
-    'CIF_DESCRIPTION',
-    ('cif', FFI_CIF),
-    ('exchange_size', lltype.Signed),
-    ('exchange_result', lltype.Signed),
-    ('exchange_args', lltype.Array(lltype.Signed,
-                          hints={'nolength': True, 'immutable': True})),
-    hints={'immutable': True})
-
-CIF_DESCRIPTION_P = lltype.Ptr(CIF_DESCRIPTION)
-W_CTypeFunc.cif_descr = lltype.nullptr(CIF_DESCRIPTION)     # default value
-
 
 # ----------
 # We attach to the classes small methods that return a 'ffi_type'
@@ -351,6 +301,16 @@
 
 
     def fb_build(self):
+        # Build a CIF_DESCRIPTION.  Actually this computes the size and
+        # allocates a larger amount of data.  It starts with a
+        # CIF_DESCRIPTION and continues with data needed for the CIF:
+        #
+        #  - the argument types, as an array of 'ffi_type *'.
+        #
+        #  - optionally, the result's and the arguments' ffi type data
+        #    (this is used only for 'struct' ffi types; in other cases the
+        #    'ffi_type *' just points to static data like 'ffi_type_sint32').
+        #
         nargs = len(self.fargs)
 
         # start with a cif_description (cif and exchange_* fields)
@@ -380,13 +340,23 @@
         exchange_offset = rffi.sizeof(rffi.CCHARP) * nargs
         exchange_offset = self.align_arg(exchange_offset)
         cif_descr.exchange_result = exchange_offset
+        cif_descr.exchange_result_libffi = exchange_offset
 
-        # then enough room for the result --- which means at least
-        # sizeof(ffi_arg), according to the ffi docs
+        if BIG_ENDIAN and self.fresult.is_primitive_integer:
+            # For results of precisely these types, libffi has a
+            # strange rule that they will be returned as a whole
+            # 'ffi_arg' if they are smaller.  The difference
+            # only matters on big-endian.
+            if self.fresult.size < SIZE_OF_FFI_ARG:
+                diff = SIZE_OF_FFI_ARG - self.fresult.size
+                cif_descr.exchange_result += diff
+
+        # then enough room for the result, rounded up to sizeof(ffi_arg)
         exchange_offset += max(rffi.getintfield(self.rtype, 'c_size'),
                                SIZE_OF_FFI_ARG)
 
         # loop over args
+        cif_descr.exchange_nb_args = len(self.fargs)
         for i, farg in enumerate(self.fargs):
             if isinstance(farg, W_CTypePointer):
                 exchange_offset += 1   # for the "must free" flag
diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py
--- a/pypy/module/_cffi_backend/ctypeobj.py
+++ b/pypy/module/_cffi_backend/ctypeobj.py
@@ -162,6 +162,9 @@
                               "cdata '%s' has no attribute '%s'",
                               self.name, attr)
 
+    def copy_and_convert_to_object(self, cdata):
+        return self.convert_to_object(cdata)
+
 
 W_CType.typedef = TypeDef(
     'CTypeDescr',
diff --git a/pypy/module/_cffi_backend/ctypevoid.py b/pypy/module/_cffi_backend/ctypevoid.py
--- a/pypy/module/_cffi_backend/ctypevoid.py
+++ b/pypy/module/_cffi_backend/ctypevoid.py
@@ -11,3 +11,6 @@
 
     def __init__(self, space):
         W_CType.__init__(self, space, -1, "void", len("void"))
+
+    def copy_and_convert_to_object(self, cdata):
+        return self.space.w_None
diff --git a/pypy/rlib/jit_libffi.py b/pypy/rlib/jit_libffi.py
new file mode 100644
--- /dev/null
+++ b/pypy/rlib/jit_libffi.py
@@ -0,0 +1,55 @@
+import sys
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib import clibffi
+
+
+FFI_CIF = clibffi.FFI_CIFP.TO
+FFI_TYPE = clibffi.FFI_TYPE_P.TO
+FFI_TYPE_P = clibffi.FFI_TYPE_P
+FFI_TYPE_PP = clibffi.FFI_TYPE_PP
+SIZE_OF_FFI_ARG = rffi.sizeof(clibffi.ffi_arg)
+
+# "cif_description" is a block of raw memory describing how to do the call.
+# It starts with a block of memory of type FFI_CIF, which is used by libffi
+# itself.  Following it, we find jit_libffi-specific information:
+#
+#  - 'exchange_size': an integer that tells how big a buffer we must
+#    allocate for the call; this buffer should have enough room at the
+#    beginning for an array of pointers to the actual argument values,
+#    which is initialized internally by jit_ffi_call().
+#
+#  - 'exchange_result': the offset in that buffer for the result of the call.
+#
+#  - 'exchange_result_libffi': the actual offset passed to ffi_call().
+#    Differs on big-endian machines if the result is an integer type smaller
+#    than SIZE_OF_FFI_ARG (blame libffi).
+#
+#  - 'exchange_args[nargs]': the offset in that buffer for each argument.
+
+CIF_DESCRIPTION = lltype.Struct(
+    'CIF_DESCRIPTION',
+    ('cif', FFI_CIF),
+    ('exchange_size', lltype.Signed),
+    ('exchange_result', lltype.Signed),
+    ('exchange_result_libffi', lltype.Signed),
+    ('exchange_nb_args', lltype.Signed),
+    ('exchange_args', lltype.Array(lltype.Signed,
+                          hints={'nolength': True, 'immutable': True})),
+    hints={'immutable': True})
+
+CIF_DESCRIPTION_P = lltype.Ptr(CIF_DESCRIPTION)
+
+
+def jit_ffi_call(cif_description, func_addr, exchange_buffer):
+    """Wrapper around ffi_call().  Must receive a CIF_DESCRIPTION_P that
+    describes the layout of the 'exchange_buffer' of size 'exchange_size'.
+    """
+    buffer_array = rffi.cast(rffi.VOIDPP, exchange_buffer)
+    for i in range(cif_description.exchange_nb_args):
+        data = rffi.ptradd(exchange_buffer, cif_description.exchange_args[i])
+        buffer_array[i] = data
+    resultdata = rffi.ptradd(exchange_buffer,
+                             cif_description.exchange_result_libffi)
+    clibffi.c_ffi_call(cif_description.cif, func_addr,
+                       rffi.cast(rffi.VOIDP, resultdata),
+                       buffer_array)


More information about the pypy-commit mailing list