[pypy-commit] pypy default: Update: ffi.addressof(lib, "funcname")
arigo
noreply at buildbot.pypy.org
Tue May 26 19:02:40 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r77589:39af68b61c76
Date: 2015-05-26 19:01 +0200
http://bitbucket.org/pypy/pypy/changeset/39af68b61c76/
Log: Update: ffi.addressof(lib, "funcname")
diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO
--- a/lib_pypy/cffi.egg-info/PKG-INFO
+++ b/lib_pypy/cffi.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: cffi
-Version: 1.0.3
+Version: 1.0.4
Summary: Foreign Function Interface for Python calling C code.
Home-page: http://cffi.readthedocs.org
Author: Armin Rigo, Maciej Fijalkowski
diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py
--- a/lib_pypy/cffi/__init__.py
+++ b/lib_pypy/cffi/__init__.py
@@ -4,8 +4,8 @@
from .api import FFI, CDefError, FFIError
from .ffiplatform import VerificationError, VerificationMissing
-__version__ = "1.0.3"
-__version_info__ = (1, 0, 3)
+__version__ = "1.0.4"
+__version_info__ = (1, 0, 4)
# The verifier module file names are based on the CRC32 of a string that
# contains the following version number. It may be older than __version__
diff --git a/lib_pypy/cffi/_cffi_include.h b/lib_pypy/cffi/_cffi_include.h
--- a/lib_pypy/cffi/_cffi_include.h
+++ b/lib_pypy/cffi/_cffi_include.h
@@ -51,6 +51,11 @@
# endif
#endif
+#ifdef __GNUC__
+# define _CFFI_UNUSED_FN __attribute__((unused))
+#else
+# define _CFFI_UNUSED_FN /* nothing */
+#endif
/********** CPython-specific section **********/
#ifndef PYPY_VERSION
@@ -82,7 +87,8 @@
PyLong_FromLongLong((long long)x)))
#define _cffi_to_c_int(o, type) \
- (sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \
+ ((type)( \
+ sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \
: (type)_cffi_to_c_i8(o)) : \
sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \
: (type)_cffi_to_c_i16(o)) : \
@@ -90,7 +96,7 @@
: (type)_cffi_to_c_i32(o)) : \
sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \
: (type)_cffi_to_c_i64(o)) : \
- (Py_FatalError("unsupported size for type " #type), (type)0))
+ (Py_FatalError("unsupported size for type " #type), (type)0)))
#define _cffi_to_c_i8 \
((int(*)(PyObject *))_cffi_exports[1])
@@ -181,6 +187,20 @@
return NULL;
}
+_CFFI_UNUSED_FN
+static PyObject **_cffi_unpack_args(PyObject *args_tuple, Py_ssize_t expected,
+ const char *fnname)
+{
+ if (PyTuple_GET_SIZE(args_tuple) != expected) {
+ PyErr_Format(PyExc_TypeError,
+ "%.150s() takes exactly %zd arguments (%zd given)",
+ fnname, expected, PyTuple_GET_SIZE(args_tuple));
+ return NULL;
+ }
+ return &PyTuple_GET_ITEM(args_tuple, 0); /* pointer to the first item,
+ the others follow */
+}
+
#endif
/********** end CPython-specific section **********/
@@ -200,12 +220,6 @@
((got_nonpos) == (expected <= 0) && \
(got) == (unsigned long long)expected)
-#ifdef __GNUC__
-# define _CFFI_UNUSED_FN __attribute__((unused))
-#else
-# define _CFFI_UNUSED_FN /* nothing */
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/lib_pypy/cffi/parse_c_type.h b/lib_pypy/cffi/parse_c_type.h
--- a/lib_pypy/cffi/parse_c_type.h
+++ b/lib_pypy/cffi/parse_c_type.h
@@ -83,7 +83,8 @@
const char *name;
void *address;
_cffi_opcode_t type_op;
- size_t size; // 0 if unknown
+ void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown
+ // OP_CPYTHON_BLTN_*: addr of direct function
};
struct _cffi_getconst_s {
diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py
--- a/lib_pypy/cffi/recompiler.py
+++ b/lib_pypy/cffi/recompiler.py
@@ -19,7 +19,7 @@
self.check_value = check_value
def as_c_expr(self):
- return ' { "%s", (void *)%s, %s, %s },' % (
+ return ' { "%s", (void *)%s, %s, (void *)%s },' % (
self.name, self.address, self.type_op.as_c_expr(), self.size)
def as_python_expr(self):
@@ -386,7 +386,7 @@
prnt('# ifdef _MSC_VER')
prnt(' PyMODINIT_FUNC')
prnt('# if PY_MAJOR_VERSION >= 3')
- prnt(' PyInit_%s(void) { return -1; }' % (base_module_name,))
+ prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,))
prnt('# else')
prnt(' init%s(void) { }' % (base_module_name,))
prnt('# endif')
@@ -602,6 +602,26 @@
else:
argname = 'args'
#
+ # ------------------------------
+ # the 'd' version of the function, only for addressof(lib, 'func')
+ arguments = []
+ call_arguments = []
+ context = 'argument of %s' % name
+ for i, type in enumerate(tp.args):
+ arguments.append(type.get_c_name(' x%d' % i, context))
+ call_arguments.append('x%d' % i)
+ repr_arguments = ', '.join(arguments)
+ repr_arguments = repr_arguments or 'void'
+ name_and_arguments = '_cffi_d_%s(%s)' % (name, repr_arguments)
+ prnt('static %s' % (tp.result.get_c_name(name_and_arguments),))
+ prnt('{')
+ call_arguments = ', '.join(call_arguments)
+ result_code = 'return '
+ if isinstance(tp.result, model.VoidType):
+ result_code = ''
+ prnt(' %s%s(%s);' % (result_code, name, call_arguments))
+ prnt('}')
+ #
prnt('#ifndef PYPY_VERSION') # ------------------------------
#
prnt('static PyObject *')
@@ -632,10 +652,13 @@
rng = range(len(tp.args))
for i in rng:
prnt(' PyObject *arg%d;' % i)
+ prnt(' PyObject **aa;')
prnt()
- prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % (
- 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng])))
+ prnt(' aa = _cffi_unpack_args(args, %d, "%s");' % (len(rng), name))
+ prnt(' if (aa == NULL)')
prnt(' return NULL;')
+ for i in rng:
+ prnt(' arg%d = aa[%d];' % (i, i))
prnt()
#
for i, type in enumerate(tp.args):
@@ -668,6 +691,7 @@
# the PyPy version: need to replace struct/union arguments with
# pointers, and if the result is a struct/union, insert a first
# arg that is a pointer to the result.
+ difference = False
arguments = []
call_arguments = []
context = 'argument of %s' % name
@@ -675,6 +699,7 @@
indirection = ''
if isinstance(type, model.StructOrUnion):
indirection = '*'
+ difference = True
arg = type.get_c_name(' %sx%d' % (indirection, i), context)
arguments.append(arg)
call_arguments.append('%sx%d' % (indirection, i))
@@ -686,18 +711,22 @@
tp_result = model.void_type
result_decl = None
result_code = '*result = '
- repr_arguments = ', '.join(arguments)
- repr_arguments = repr_arguments or 'void'
- name_and_arguments = '_cffi_f_%s(%s)' % (name, repr_arguments)
- prnt('static %s' % (tp_result.get_c_name(name_and_arguments),))
- prnt('{')
- if result_decl:
- prnt(result_decl)
- call_arguments = ', '.join(call_arguments)
- prnt(' { %s%s(%s); }' % (result_code, name, call_arguments))
- if result_decl:
- prnt(' return result;')
- prnt('}')
+ difference = True
+ if difference:
+ repr_arguments = ', '.join(arguments)
+ repr_arguments = repr_arguments or 'void'
+ name_and_arguments = '_cffi_f_%s(%s)' % (name, repr_arguments)
+ prnt('static %s' % (tp_result.get_c_name(name_and_arguments),))
+ prnt('{')
+ if result_decl:
+ prnt(result_decl)
+ call_arguments = ', '.join(call_arguments)
+ prnt(' { %s%s(%s); }' % (result_code, name, call_arguments))
+ if result_decl:
+ prnt(' return result;')
+ prnt('}')
+ else:
+ prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name))
#
prnt('#endif') # ------------------------------
prnt()
@@ -718,7 +747,8 @@
meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS'
self._lsts["global"].append(
GlobalExpr(name, '_cffi_f_%s' % name,
- CffiOp(meth_kind, type_index), check_value=0))
+ CffiOp(meth_kind, type_index), check_value=0,
+ size='_cffi_d_%s' % name))
# ----------
# named structs or unions
diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py
--- a/lib_pypy/cffi/vengine_cpy.py
+++ b/lib_pypy/cffi/vengine_cpy.py
@@ -886,7 +886,8 @@
PyLong_FromLongLong((long long)x)))
#define _cffi_to_c_int(o, type) \
- (sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \
+ ((type)( \
+ sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \
: (type)_cffi_to_c_i8(o)) : \
sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \
: (type)_cffi_to_c_i16(o)) : \
@@ -894,7 +895,7 @@
: (type)_cffi_to_c_i32(o)) : \
sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \
: (type)_cffi_to_c_i64(o)) : \
- (Py_FatalError("unsupported size for type " #type), (type)0))
+ (Py_FatalError("unsupported size for type " #type), (type)0)))
#define _cffi_to_c_i8 \
((int(*)(PyObject *))_cffi_exports[1])
diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -2,7 +2,7 @@
from pypy.interpreter.mixedmodule import MixedModule
from rpython.rlib import rdynload
-VERSION = "1.0.3"
+VERSION = "1.0.4"
class Module(MixedModule):
diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -201,13 +201,13 @@
in case of nested structures or arrays.
3. ffi.addressof(<library>, "name") returns the address of the named
-global variable."""
+function or global variable."""
#
from pypy.module._cffi_backend.lib_obj import W_LibObject
space = self.space
if isinstance(w_arg, W_LibObject) and len(args_w) == 1:
# case 3 in the docstring
- return w_arg.address_of_global_var(space.str_w(args_w[0]))
+ return w_arg.address_of_func_or_global_var(space.str_w(args_w[0]))
#
w_ctype = self.ffi_type(w_arg, ACCEPT_CDATA)
if len(args_w) == 0:
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
@@ -64,7 +64,7 @@
#
ptr = rffi.cast(rffi.CCHARP, g.c_address)
assert ptr
- return W_FunctionWrapper(self.space, ptr, w_ct,
+ return W_FunctionWrapper(self.space, ptr, g.c_size_or_direct_fn, w_ct,
locs, rawfunctype, fnname)
@jit.elidable_promote()
@@ -104,7 +104,7 @@
# A global variable of the exact type specified here
w_ct = realize_c_type.realize_c_type(
self.ffi, self.ctx.c_types, getarg(g.c_type_op))
- g_size = rffi.getintfield(g, 'c_size')
+ g_size = rffi.cast(lltype.Signed, g.c_size_or_direct_fn)
if g_size != w_ct.size and g_size != 0 and w_ct.size > 0:
raise oefmt(self.ffi.w_FFIError,
"global variable '%s' should be %d bytes "
@@ -197,7 +197,7 @@
for i in range(total)]
return space.newlist(names_w)
- def address_of_global_var(self, varname):
+ def address_of_func_or_global_var(self, varname):
# rebuild a string object from 'varname', to do typechecks and
# to force a unicode back to a plain string
space = self.space
@@ -206,9 +206,15 @@
# regular case: a global variable
return w_value.address()
#
- if ((isinstance(w_value, W_CData) and
- isinstance(w_value.ctype, W_CTypeFunc))
- or isinstance(w_value, W_FunctionWrapper)):
+ 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)
+ else:
+ return w_value # backward compatibility
+ #
+ if (isinstance(w_value, W_CData) and
+ isinstance(w_value.ctype, W_CTypeFunc)):
# '&func' is 'func' in C, for a constant function 'func'
return w_value
#
diff --git a/pypy/module/_cffi_backend/parse_c_type.py b/pypy/module/_cffi_backend/parse_c_type.py
--- a/pypy/module/_cffi_backend/parse_c_type.py
+++ b/pypy/module/_cffi_backend/parse_c_type.py
@@ -23,7 +23,7 @@
('name', rffi.CCHARP),
('address', rffi.VOIDP),
('type_op', _CFFI_OPCODE_T),
- ('size', rffi.SIZE_T))
+ ('size_or_direct_fn', rffi.CCHARP))
CDL_INTCONST_S = lltype.Struct('cdl_intconst_s',
('value', rffi.ULONGLONG),
('neg', rffi.INT))
diff --git a/pypy/module/_cffi_backend/src/parse_c_type.h b/pypy/module/_cffi_backend/src/parse_c_type.h
--- a/pypy/module/_cffi_backend/src/parse_c_type.h
+++ b/pypy/module/_cffi_backend/src/parse_c_type.h
@@ -1,5 +1,5 @@
-/* See doc/parse_c_type.rst in the source of CFFI for more information */
+/* See doc/misc/parse_c_type.rst in the source of CFFI for more information */
typedef void *_cffi_opcode_t;
@@ -83,7 +83,8 @@
const char *name;
void *address;
_cffi_opcode_t type_op;
- size_t size; // 0 if unknown
+ void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown
+ // OP_CPYTHON_BLTN_*: addr of direct function
};
struct _cffi_getconst_s {
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -3335,4 +3335,4 @@
def test_version():
# this test is here mostly for PyPy
- assert __version__ == "1.0.3"
+ assert __version__ == "1.0.4"
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
@@ -9,11 +9,14 @@
@unwrap_spec(cdef=str, module_name=str, source=str)
def prepare(space, cdef, module_name, source, w_includes=None):
try:
+ import cffi
from cffi import FFI # <== the system one, which
- from cffi import recompiler # needs to be at least cffi 1.0.0
+ from cffi import recompiler # needs to be at least cffi 1.0.4
from cffi import ffiplatform
except ImportError:
py.test.skip("system cffi module not found or older than 1.0.0")
+ if cffi.__version_info__ < (1, 0, 4):
+ py.test.skip("system cffi module needs to be at least 1.0.4")
space.appexec([], """():
import _cffi_backend # force it to be initialized
""")
@@ -739,7 +742,6 @@
#
raises(AttributeError, ffi.addressof, lib, 'unknown_var')
raises(AttributeError, ffi.addressof, lib, "FOOBAR")
- assert ffi.addressof(lib, 'FetchRectBottom') == lib.FetchRectBottom
def test_defines__CFFI_(self):
# Check that we define the macro _CFFI_ automatically.
@@ -782,3 +784,18 @@
assert str(e5.value) == "foo2() takes exactly 2 arguments (0 given)"
assert str(e6.value) == "foo2() takes exactly 2 arguments (1 given)"
assert str(e7.value) == "foo2() takes exactly 2 arguments (3 given)"
+
+ def test_address_of_function(self):
+ ffi, lib = self.prepare(
+ "long myfunc(long x);",
+ "test_addressof_function",
+ "char myfunc(char x) { return (char)(x + 42); }")
+ assert lib.myfunc(5) == 47
+ assert lib.myfunc(0xABC05) == 47
+ assert not isinstance(lib.myfunc, ffi.CData)
+ assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(long)")
+ addr = ffi.addressof(lib, 'myfunc')
+ assert addr(5) == 47
+ assert addr(0xABC05) == 47
+ assert isinstance(addr, ffi.CData)
+ assert ffi.typeof(addr) == ffi.typeof("long(*)(long)")
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
@@ -22,13 +22,15 @@
"""
_immutable_ = True
- def __init__(self, space, fnptr, ctype, locs, rawfunctype, fnname):
+ def __init__(self, space, fnptr, directfnptr, ctype,
+ locs, rawfunctype, fnname):
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)
#
self.space = space
self.fnptr = fnptr
+ self.directfnptr = directfnptr
self.ctype = ctype
self.locs = locs
self.rawfunctype = rawfunctype
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
@@ -761,7 +761,6 @@
#
py.test.raises(AttributeError, ffi.addressof, lib, 'unknown_var')
py.test.raises(AttributeError, ffi.addressof, lib, "FOOBAR")
- assert ffi.addressof(lib, 'FetchRectBottom') == lib.FetchRectBottom
def test_defines__CFFI_():
# Check that we define the macro _CFFI_ automatically.
@@ -777,3 +776,48 @@
#endif
""")
assert lib.CORRECT == 1
+
+def test_unpack_args():
+ ffi = FFI()
+ ffi.cdef("void foo0(void); void foo1(int); void foo2(int, int);")
+ lib = verify(ffi, "test_unpack_args", """
+ void foo0(void) { }
+ void foo1(int x) { }
+ void foo2(int x, int y) { }
+ """)
+ assert 'foo0' in repr(lib.foo0)
+ assert 'foo1' in repr(lib.foo1)
+ assert 'foo2' in repr(lib.foo2)
+ lib.foo0()
+ lib.foo1(42)
+ lib.foo2(43, 44)
+ e1 = py.test.raises(TypeError, lib.foo0, 42)
+ e2 = py.test.raises(TypeError, lib.foo0, 43, 44)
+ e3 = py.test.raises(TypeError, lib.foo1)
+ e4 = py.test.raises(TypeError, lib.foo1, 43, 44)
+ e5 = py.test.raises(TypeError, lib.foo2)
+ e6 = py.test.raises(TypeError, lib.foo2, 42)
+ e7 = py.test.raises(TypeError, lib.foo2, 45, 46, 47)
+ assert str(e1.value) == "foo0() takes no arguments (1 given)"
+ assert str(e2.value) == "foo0() takes no arguments (2 given)"
+ assert str(e3.value) == "foo1() takes exactly one argument (0 given)"
+ assert str(e4.value) == "foo1() takes exactly one argument (2 given)"
+ assert str(e5.value) == "foo2() takes exactly 2 arguments (0 given)"
+ assert str(e6.value) == "foo2() takes exactly 2 arguments (1 given)"
+ assert str(e7.value) == "foo2() takes exactly 2 arguments (3 given)"
+
+def test_address_of_function():
+ ffi = FFI()
+ ffi.cdef("long myfunc(long x);")
+ lib = verify(ffi, "test_addressof_function", """
+ char myfunc(char x) { return (char)(x + 42); }
+ """)
+ assert lib.myfunc(5) == 47
+ assert lib.myfunc(0xABC05) == 47
+ assert not isinstance(lib.myfunc, ffi.CData)
+ assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(long)")
+ addr = ffi.addressof(lib, 'myfunc')
+ assert addr(5) == 47
+ assert addr(0xABC05) == 47
+ assert isinstance(addr, ffi.CData)
+ assert ffi.typeof(addr) == ffi.typeof("long(*)(long)")
More information about the pypy-commit
mailing list