[pypy-commit] pypy reflex-support: refactoring for cleanup and to recover the speed lost for the void**/object** converters

wlav noreply at buildbot.pypy.org
Tue May 8 06:07:17 CEST 2012


Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r54954:1a776d4b2018
Date: 2012-05-07 17:12 -0700
http://bitbucket.org/pypy/pypy/changeset/1a776d4b2018/

Log:	refactoring for cleanup and to recover the speed lost for the
	void**/object** converters

diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py
--- a/pypy/module/cppyy/converter.py
+++ b/pypy/module/cppyy/converter.py
@@ -42,6 +42,7 @@
 class TypeConverter(object):
     _immutable_ = True
     libffitype = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+    uses_local = False
 
     name = ""
 
@@ -178,6 +179,7 @@
 class ConstRefNumericTypeConverterMixin(NumericTypeConverterMixin):
     _mixin_ = True
     _immutable_ = True
+    uses_local = True
 
     def convert_argument_libffi(self, space, w_obj, argchain):
         obj = self._unwrap_object(space, w_obj)
@@ -519,6 +521,7 @@
 
 class VoidPtrPtrConverter(TypeConverter):
     _immutable_ = True
+    uses_local = True
 
     def convert_argument(self, space, w_obj, address, call_local):
         r = rffi.cast(rffi.VOIDPP, call_local)
@@ -682,6 +685,7 @@
 
 class InstancePtrPtrConverter(InstancePtrConverter):
     _immutable_ = True
+    uses_local = True
 
     def convert_argument(self, space, w_obj, address, call_local):
         r = rffi.cast(rffi.VOIDPP, call_local)
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
@@ -112,55 +112,68 @@
     """ A concrete function after overloading has been resolved """
     _immutable_ = True
     
-    def __init__(self, space, containing_scope, method_index, result_type, arg_defs, args_required):
+    def __init__(self, space, containing_scope, method_index, arg_defs, args_required):
         self.space = space
         self.scope = containing_scope
         self.index = method_index
         self.cppmethod = capi.c_get_method(self.scope, method_index)
         self.arg_defs = arg_defs
         self.args_required = args_required
-        self.result_type = result_type
+        self.args_expected = len(arg_defs)
 
         # Setup of the method dispatch's innards is done lazily, i.e. only when
         # the method is actually used.
-        self.arg_converters = None
+        self.converters = None
         self.executor = None
         self._libffifunc = None
 
-    def _address_from_local_buffer(self, call_local, index):
-        return lltype.direct_ptradd(rffi.cast(rffi.CCHARP, call_local), index*rffi.sizeof(rffi.VOIDP))
+    def _address_from_local_buffer(self, call_local, idx):
+        if not call_local:
+            return call_local
+        stride = rffi.sizeof(rffi.VOIDP)
+        loc_idx = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, call_local), idx*stride)
+        return rffi.cast(rffi.VOIDP, loc_idx)
 
     @jit.unroll_safe
     def call(self, cppthis, args_w):
         jit.promote(self)
         assert lltype.typeOf(cppthis) == capi.C_OBJECT
+
+        # check number of given arguments against required (== total - defaults)
         args_expected = len(self.arg_defs)
         args_given = len(args_w)
         if args_expected < args_given or args_given < self.args_required:
             raise OperationError(self.space.w_TypeError,
                                  self.space.wrap("wrong number of arguments"))
 
-        if self.arg_converters is None:
+        # initial setup of converters, executors, and libffi (if available)
+        if self.converters is None:
             self._setup(cppthis)
 
-        call_local = lltype.malloc(rffi.CArray(rffi.VOIDP), len(args_w), flavor='raw')
+        # some calls, e.g. for ptr-ptr or reference need a local array to store data for
+        # the duration of the call
+        if [conv for conv in self.converters if conv.uses_local]:
+            call_local = rffi.lltype.malloc(rffi.VOIDP.TO, len(args_w), flavor='raw')
+        else:
+            call_local = lltype.nullptr(rffi.VOIDP.TO)
 
-        if self._libffifunc:
+        try:
+            # attempt to call directly through ffi chain
+            if self._libffifunc:
+                try:
+                    return self.do_fast_call(cppthis, args_w, call_local)
+                except FastCallNotPossible:
+                    pass      # can happen if converters or executor does not implement ffi
+
+            # ffi chain must have failed; using stub functions instead
+            args = self.prepare_arguments(args_w, call_local)
             try:
-                result = self.do_fast_call(cppthis, args_w, call_local)
+                return self.executor.execute(self.space, self.cppmethod, cppthis, len(args_w), args)
+            finally:
+                self.finalize_call(args, args_w, call_local)
+        finally:
+            if call_local:
                 lltype.free(call_local, flavor='raw')
-                return result
-            except FastCallNotPossible:
-                pass          # can happen if converters or executor does not implement ffi
-            except:
-                lltype.free(call_local, flavor='raw')
-                raise
-
-        args = self.prepare_arguments(args_w, call_local)
-        try:
-            return self.executor.execute(self.space, self.cppmethod, cppthis, len(args_w), args)
-        finally:
-            self.finalize_call(args, args_w, call_local)
 
     @jit.unroll_safe
     def do_fast_call(self, cppthis, args_w, call_local):
@@ -171,13 +184,13 @@
         refbuffers = []
         try:
             for i in range(len(args_w)):
-                conv = self.arg_converters[i]
+                conv = self.converters[i]
                 w_arg = args_w[i]
                 refbuf = conv.convert_argument_libffi(self.space, w_arg, argchain)
                 if refbuf:
                     refbuffers.append(refbuf)
             for j in range(i+1, len(self.arg_defs)):
-                conv = self.arg_converters[j]
+                conv = self.converters[j]
                 conv.default_argument_libffi(self.space, argchain)
             return self.executor.execute_libffi(self.space, self._libffifunc, argchain)
         finally:
@@ -185,9 +198,9 @@
                 lltype.free(refbuf, flavor='raw')
 
     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]
-        self.executor = executor.get_executor(self.space, self.result_type)
+        self.converters = [converter.get_converter(self.space, arg_type, arg_dflt)
+                               for arg_type, arg_dflt in self.arg_defs]
+        self.executor = executor.get_executor(self.space, capi.c_method_result_type(self.scope, self.index))
 
         # Each CPPMethod corresponds one-to-one to a C++ equivalent and cppthis
         # has been offset to the matching class. Hence, the libffi pointer is
@@ -195,9 +208,8 @@
         methgetter = capi.c_get_methptr_getter(self.scope, self.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
+            argtypes_libffi = [conv.libffitype for conv in self.converters if conv.libffitype]
+            if (len(argtypes_libffi) == len(self.converters) and
                     self.executor.libffitype):
                 # add c++ this to the arguments
                 libffifunc = libffi.Func("XXX",
@@ -211,7 +223,7 @@
         args = capi.c_allocate_function_args(len(args_w))
         stride = capi.c_function_arg_sizeof()
         for i in range(len(args_w)):
-            conv = self.arg_converters[i]
+            conv = self.converters[i]
             w_arg = args_w[i]
             try:
                 arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
@@ -220,12 +232,11 @@
             except:
                 # fun :-(
                 for j in range(i):
-                    conv = self.arg_converters[j]
+                    conv = self.converters[j]
                     arg_j = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), j*stride)
                     loc_j = self._address_from_local_buffer(call_local, j)
                     conv.free_argument(rffi.cast(capi.C_OBJECT, arg_j), loc_j)
                 capi.c_deallocate_function_args(args)
-                lltype.free(call_local, flavor='raw')
                 raise
         return args
 
@@ -233,13 +244,12 @@
     def finalize_call(self, args, args_w, call_local):
         stride = capi.c_function_arg_sizeof()
         for i in range(len(args_w)):
-            conv = self.arg_converters[i]
+            conv = self.converters[i]
             arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
             loc_i = self._address_from_local_buffer(call_local, i)
             conv.finalize_call(self.space, args_w[i], loc_i)
             conv.free_argument(rffi.cast(capi.C_OBJECT, arg_i), loc_i)
         capi.c_deallocate_function_args(args)
-        lltype.free(call_local, flavor='raw')
 
     def signature(self):
         return capi.c_method_signature(self.scope, self.index)
@@ -485,7 +495,6 @@
     kind = "namespace"
 
     def _make_cppfunction(self, method_index):
-        result_type = capi.c_method_result_type(self, method_index)
         num_args = capi.c_method_num_args(self, method_index)
         args_required = capi.c_method_req_args(self, method_index)
         arg_defs = []
@@ -493,7 +502,7 @@
             arg_type = capi.c_method_arg_type(self, method_index, i)
             arg_dflt = capi.c_method_arg_default(self, method_index, i)
             arg_defs.append((arg_type, arg_dflt))
-        return CPPFunction(self.space, self, method_index, result_type, arg_defs, args_required)
+        return CPPFunction(self.space, self, method_index, arg_defs, args_required)
 
     def _make_datamember(self, dm_name, dm_idx):
         type_name = capi.c_datamember_type(self, dm_idx)
@@ -551,7 +560,6 @@
     kind = "class"
 
     def _make_cppfunction(self, method_index):
-        result_type = capi.c_method_result_type(self, method_index)
         num_args = capi.c_method_num_args(self, method_index)
         args_required = capi.c_method_req_args(self, method_index)
         arg_defs = []
@@ -560,13 +568,12 @@
             arg_dflt = capi.c_method_arg_default(self, method_index, i)
             arg_defs.append((arg_type, arg_dflt))
         if capi.c_is_constructor(self, method_index):
-            result_type = "constructor"
             cls = CPPConstructor
         elif capi.c_is_staticmethod(self, method_index):
             cls = CPPFunction
         else:
             cls = CPPMethod
-        return cls(self.space, self, method_index, result_type, arg_defs, args_required)
+        return cls(self.space, self, method_index, arg_defs, args_required)
 
     def _find_datamembers(self):
         num_datamembers = capi.c_num_datamembers(self)
diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx
--- a/pypy/module/cppyy/src/cintcwrapper.cxx
+++ b/pypy/module/cppyy/src/cintcwrapper.cxx
@@ -546,7 +546,14 @@
 }
 
 char* cppyy_method_result_type(cppyy_scope_t handle, int method_index) {
-    TFunction* f = type_get_method(handle, method_index);
+    TFunction* f = 0;
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass()) {
+        if (cppyy_is_constructor(handle, method_index))
+            return cppstring_to_cstring("constructor");
+        f = (TFunction*)cr->GetListOfMethods()->At(method_index);
+    else
+        f = &g_globalfuncs[method_index];
     return type_cppstring_to_cstring(f->GetReturnTypeName());
 }
 
diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx
--- a/pypy/module/cppyy/src/reflexcwrapper.cxx
+++ b/pypy/module/cppyy/src/reflexcwrapper.cxx
@@ -340,6 +340,8 @@
 char* cppyy_method_result_type(cppyy_scope_t handle, int method_index) {
     Reflex::Scope s = scope_from_handle(handle);
     Reflex::Member m = s.FunctionMemberAt(method_index);
+    if (m.IsConstructor())
+        return cppstring_to_cstring("constructor");
     Reflex::Type rt = m.TypeOf().ReturnType();
     std::string name = rt.Name(Reflex::FINAL|Reflex::SCOPED|Reflex::QUALIFIED);
     return cppstring_to_cstring(name);


More information about the pypy-commit mailing list