[pypy-commit] pypy reflex-support: optimize construction of libffi function for methods
wlav
noreply at buildbot.pypy.org
Thu Feb 16 19:42:22 CET 2012
Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r52560:769f8f7bb605
Date: 2012-02-16 10:40 -0800
http://bitbucket.org/pypy/pypy/changeset/769f8f7bb605/
Log: optimize construction of libffi function for methods
diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py
--- a/pypy/module/cppyy/interp_cppyy.py
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -84,15 +84,10 @@
)
W_CPPLibrary.typedef.acceptable_as_base_class = True
- at jit.elidable_promote()
-def get_methptr_getter(handle, method_index):
- return capi.c_get_methptr_getter(handle, method_index)
-
class CPPMethod(object):
""" A concrete function after overloading has been resolved """
_immutable_ = True
- _immutable_fields_ = ["_libffifunc_cache[*]", "arg_converters[*]"]
def __init__(self, cpptype, method_index, result_type, arg_defs, args_required):
self.cpptype = cpptype
@@ -101,11 +96,11 @@
self.arg_defs = arg_defs
self.args_required = args_required
self.executor = executor.get_executor(self.space, result_type)
+
+ # Setup of the method dispatch's innards is done lazily, i.e. only when
+ # the method is actually used. TODO: executor should be lazy as well.
self.arg_converters = None
- methgetter = get_methptr_getter(self.cpptype.handle,
- self.method_index)
- self.methgetter = methgetter
- self._libffifunc_cache = {}
+ self._libffifunc = None
@jit.unroll_safe
def call(self, cppthis, w_type, args_w):
@@ -117,11 +112,14 @@
if args_expected < args_given or args_given < self.args_required:
raise TypeError("wrong number of arguments")
- if self.methgetter and cppthis: # only for methods
+ if self.arg_converters is None:
+ self._setup(cppthis)
+
+ if self._libffifunc:
try:
return self.do_fast_call(cppthis, w_type, args_w)
except FastCallNotPossible:
- pass
+ pass # can happen if converters or executor does not implement ffi
args = self.prepare_arguments(args_w)
try:
@@ -132,11 +130,6 @@
@jit.unroll_safe
def do_fast_call(self, cppthis, w_type, args_w):
jit.promote(self)
- funcptr = self.methgetter(rffi.cast(capi.C_OBJECT, cppthis))
- libffi_func = self._prepare_libffi_func(funcptr)
- if not libffi_func:
- raise FastCallNotPossible
-
argchain = libffi.ArgChain()
argchain.arg(cppthis)
i = len(self.arg_defs)
@@ -147,37 +140,31 @@
for j in range(i+1, len(self.arg_defs)):
conv = self.arg_converters[j]
conv.default_argument_libffi(self.space, argchain)
- return self.executor.execute_libffi(self.space, w_type, libffi_func, argchain)
+ return self.executor.execute_libffi(self.space, w_type, self._libffifunc, argchain)
- @jit.elidable_promote()
- def _prepare_libffi_func(self, funcptr):
- key = rffi.cast(rffi.LONG, funcptr)
- if key in self._libffifunc_cache:
- return self._libffifunc_cache[key]
- if self.arg_converters is None:
- self._build_converters()
- argtypes_libffi = [conv.libffitype for conv in self.arg_converters
- if conv.libffitype]
- if (len(argtypes_libffi) == len(self.arg_converters) and
- self.executor.libffitype):
- # add c++ this to the arguments
- libffifunc = libffi.Func("XXX",
- [libffi.types.pointer] + argtypes_libffi,
- self.executor.libffitype, funcptr)
- else:
- libffifunc = None
- self._libffifunc_cache[key] = libffifunc
- return libffifunc
-
- def _build_converters(self):
+ def _setup(self, cppthis):
self.arg_converters = [converter.get_converter(self.space, arg_type, arg_dflt)
for arg_type, arg_dflt in self.arg_defs]
+ # Each CPPMethod corresponds one-to-one to a C++ equivalent and cppthis
+ # has been offset to the matching class. Hence, the libffi pointer is
+ # uniquely defined and needs to be setup only once.
+ methgetter = capi.c_get_methptr_getter(self.cpptype.handle, self.method_index)
+ if methgetter and cppthis: # methods only for now
+ funcptr = methgetter(rffi.cast(capi.C_OBJECT, cppthis))
+ argtypes_libffi = [conv.libffitype for conv in self.arg_converters
+ if conv.libffitype]
+ if (len(argtypes_libffi) == len(self.arg_converters) and
+ self.executor.libffitype):
+ # add c++ this to the arguments
+ libffifunc = libffi.Func("XXX",
+ [libffi.types.pointer] + argtypes_libffi,
+ self.executor.libffitype, funcptr)
+ self._libffifunc = libffifunc
+
@jit.unroll_safe
def prepare_arguments(self, args_w):
jit.promote(self)
- if self.arg_converters is None:
- self._build_converters()
args = capi.c_allocate_function_args(len(args_w))
stride = capi.c_function_arg_sizeof()
for i in range(len(args_w)):
diff --git a/pypy/module/cppyy/test/test_pythonify.py b/pypy/module/cppyy/test/test_pythonify.py
--- a/pypy/module/cppyy/test/test_pythonify.py
+++ b/pypy/module/cppyy/test/test_pythonify.py
@@ -279,7 +279,18 @@
assert g(11., 2) == 2.
assert g(11.) == 11.
- def test11_underscore_in_class_name(self):
+ def test11_overload_on_arguments(self):
+ """Test functions overloaded on arguments"""
+
+ import cppyy
+ e = cppyy.gbl.example01(1)
+
+ assert e.addDataToInt(2) == 3
+ assert e.overloadedAddDataToInt(3) == 4
+ assert e.overloadedAddDataToInt(4, 5) == 10
+ assert e.overloadedAddDataToInt(6, 7, 8) == 22
+
+ def test12_underscore_in_class_name(self):
"""Test recognition of '_' as part of a valid class name"""
import cppyy
More information about the pypy-commit
mailing list