[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