Commits

wlav  committed 4fd9f26

second waypoint towards a loadable capi

  • Participants
  • Parent commits bd29d44
  • Branches reflex-support

Comments (0)

Files changed (6)

File pypy/module/cppyy/capi/__init__.py

 # the selection of the desired backend (default is Reflex).
 
 # choose C-API access method:
-#from pypy.module.cppyy.capi.loadable_capi import *
-from pypy.module.cppyy.capi.builtin_capi import *
+from pypy.module.cppyy.capi.loadable_capi import *
+#from pypy.module.cppyy.capi.builtin_capi import *
 
 from pypy.module.cppyy.capi.capi_types import C_OBJECT,\
     C_NULL_TYPE, C_NULL_OBJECT

File pypy/module/cppyy/capi/builtin_capi.py

     threadsafe=ts_reflect,
     compilation_info=backend.eci,
     elidable_function=True)
-def c_get_methptr_getter(cppscope, index):
+def c_get_methptr_getter(space, cppscope, index):
     return _c_get_methptr_getter(cppscope.handle, index)
 
 # handling of function argument buffer ---------------------------------------
-c_allocate_function_args = rffi.llexternal(
+_c_allocate_function_args = rffi.llexternal(
     "cppyy_allocate_function_args",
     [rffi.SIZE_T], rffi.VOIDP,
     threadsafe=ts_memory,
     compilation_info=backend.eci)
-c_deallocate_function_args = rffi.llexternal(
+def c_allocate_function_args(space, size):
+    return _c_allocate_function_args(size)
+_c_deallocate_function_args = rffi.llexternal(
     "cppyy_deallocate_function_args",
     [rffi.VOIDP], lltype.Void,
     threadsafe=ts_memory,
     compilation_info=backend.eci)
-c_function_arg_sizeof = rffi.llexternal(
+def c_deallocate_function_args(space, args):
+    _c_deallocate_function_args(args)
+_c_function_arg_sizeof = rffi.llexternal(
     "cppyy_function_arg_sizeof",
     [], rffi.SIZE_T,
     threadsafe=ts_memory,
     compilation_info=backend.eci,
     elidable_function=True)
-c_function_arg_typeoffset = rffi.llexternal(
+def c_function_arg_sizeof(space):
+    return _c_function_arg_sizeof()
+_c_function_arg_typeoffset = rffi.llexternal(
     "cppyy_function_arg_typeoffset",
     [], rffi.SIZE_T,
     threadsafe=ts_memory,
     compilation_info=backend.eci,
     elidable_function=True)
+def c_function_arg_typeoffset(space):
+    return _c_function_arg_typeoffset()
 
 # scope reflection information -----------------------------------------------
-c_is_namespace = rffi.llexternal(
+_c_is_namespace = rffi.llexternal(
     "cppyy_is_namespace",
     [C_SCOPE], rffi.INT,
     threadsafe=ts_reflect,
     compilation_info=backend.eci)
-c_is_enum = rffi.llexternal(
+def c_is_namespace(space, scope):
+    return _c_is_namespace(scope)
+_c_is_enum = rffi.llexternal(
     "cppyy_is_enum",
     [rffi.CCHARP], rffi.INT,
     threadsafe=ts_reflect,
     compilation_info=backend.eci)
+def c_is_enum(space, name):
+    return _c_is_enum(name)
 
 # type/class reflection information ------------------------------------------
 _c_final_name = rffi.llexternal(
     compilation_info=backend.eci,
     elidable_function=True)
 @jit.elidable_promote()
-def c_is_subtype(derived, base):
+def c_is_subtype(space, derived, base):
     if derived == base:
         return 1
     return _c_is_subtype(derived.handle, base.handle)
     compilation_info=backend.eci,
     elidable_function=True)
 @jit.elidable_promote()
-def c_base_offset(derived, base, address, direction):
+def c_base_offset(space, derived, base, address, direction):
     if derived == base:
         return 0
     return _c_base_offset(derived.handle, base.handle, address, direction)
-def c_base_offset1(derived_h, base, address, direction):
+@jit.elidable_promote()
+def c_base_offset1(space, derived_h, base, address, direction):
     return _c_base_offset(derived_h, base.handle, address, direction)
 
 # method/function reflection information -------------------------------------
     [C_SCOPE], rffi.INT,
     threadsafe=ts_reflect,
     compilation_info=backend.eci)
-def c_num_methods(cppscope):
+def c_num_methods(space, cppscope):
     return _c_num_methods(cppscope.handle)
 _c_method_index_at = rffi.llexternal(
     "cppyy_method_index_at",
     [C_SCOPE, rffi.INT], C_INDEX,
     threadsafe=ts_reflect,
     compilation_info=backend.eci)
-def c_method_index_at(cppscope, imethod):
+def c_method_index_at(space, cppscope, imethod):
     return _c_method_index_at(cppscope.handle, imethod)
 _c_method_indices_from_name = rffi.llexternal(
     "cppyy_method_indices_from_name",

File pypy/module/cppyy/capi/loadable_capi.py

-import atexit
-
 from rpython.rtyper.lltypesystem import rffi, lltype
-from rpython.rlib import jit, rdynload, objectmodel
+from rpython.rlib import jit, jit_libffi, rdynload, objectmodel
 from rpython.tool import leakfinder
 
 from pypy.interpreter.error import OperationError
 
+from pypy.module._cffi_backend import ctypefunc, ctypeprim, ctypeptr, misc
+
 from pypy.module.cppyy.capi.capi_types import C_SCOPE, C_TYPE, C_OBJECT,\
-   C_METHOD, C_INDEX, C_INDEX_ARRAY, WLAVC_INDEX,\
-   C_METHPTRGETTER, C_METHPTRGETTER_PTR
+   C_METHOD, C_INDEX, C_INDEX_ARRAY, WLAVC_INDEX, C_METHPTRGETTER_PTR
 
 import reflex_capi as backend
 
 def identify():
     return 'loadable_capi'
 
+class _Arg:         # poor man's union
+    _immutable_ = True
+    def __init__(self, l = 0, s = '', vp = rffi.cast(rffi.VOIDP, 0) ):
+        self._long = l
+        self._string = s
+        self._voidp = vp
+
+# For the loadable CAPI, the calls start and end in RPython. Therefore, the standard
+# _call of W_CTypeFunc, which expects wrapped objects, does not quite work: some
+# vars (e.g. void* equivalent) can not be wrapped, and others (such as rfloat) risk
+# rounding problems. This W_RCTypeFun then, takes args, instead of args_w. Note that
+# rcall() is a new method, so as to not interfere with the base class call and _call
+# when rtyping. It is also called directly (see call_capi below).
+class W_RCTypeFunc(ctypefunc.W_CTypeFunc):
+    @jit.unroll_safe
+    def rcall(self, funcaddr, args):
+        assert self.cif_descr
+        self = jit.promote(self)
+        # no checking of len(args) needed, as calls in this context are not dynamic
+
+        # The following code is functionally similar to W_CTypeFunc._call, but its
+        # implementation is tailored to the restricted use (include memory handling)
+        # of the CAPI calls.
+        space = self.space
+        cif_descr = self.cif_descr
+        size = cif_descr.exchange_size
+        raw_string = rffi.cast(rffi.CCHARP, 0)    # only ever have one in the CAPI
+        buffer = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
+        try:
+            for i in range(len(args)):
+                data = rffi.ptradd(buffer, cif_descr.exchange_args[i])
+                obj = args[i]
+                argtype = self.fargs[i]
+                # the following is clumsy, but the data types used as arguments are
+                # very limited, so it'll do for now
+                if isinstance(argtype, ctypeprim.W_CTypePrimitiveSigned):
+                    misc.write_raw_integer_data(data, rffi.cast(rffi.LONG, obj._long), argtype.size)
+                elif isinstance(argtype, ctypeprim.W_CTypePrimitiveUnsigned):
+                    misc.write_raw_integer_data(data, rffi.cast(rffi.ULONG, obj._long), argtype.size)
+                elif obj._voidp != rffi.cast(rffi.VOIDP, 0):
+                    data = rffi.cast(rffi.VOIDPP, data)
+                    data[0] = obj._voidp
+                else:    # only other use is sring
+                    n = len(obj._string)
+                    assert raw_string == rffi.cast(rffi.CCHARP, 0)
+                    raw_string = lltype.malloc(rffi.CCHARP.TO, n+1, flavor='raw')
+                    for j in range(n):
+                        raw_string[j] = obj._string[j]
+                    raw_string[n] = '\x00'
+                    data = rffi.cast(rffi.CCHARPP, data)
+                    data[0] = raw_string
+
+            jit_libffi.jit_ffi_call(cif_descr,
+                                    rffi.cast(rffi.VOIDP, funcaddr),
+                                    buffer)
+
+            resultdata = rffi.ptradd(buffer, cif_descr.exchange_result)
+        finally:
+            if raw_string != rffi.cast(rffi.CCHARP, 0):
+                lltype.free(raw_string, flavor='raw')
+            lltype.free(buffer, flavor='raw')
+        return rffi.cast(rffi.LONGP, resultdata)
+
 std_string_name = backend.std_string_name
 
 ts_reflect = backend.ts_reflect
         c_double = nt.new_primitive_type(space, 'double')
 
         c_ccharp = nt.new_pointer_type(space, c_char)
-        c_voidp  = nt.new_primitive_type(space, 'unsigned long') # b/c voidp can not be wrapped
+        c_index_array = nt.new_primitive_type(space, 'unsigned long')     # likewise ...
+
+        c_voidp  = nt.new_pointer_type(space, c_void)
+        c_size_t = nt.new_primitive_type(space, 'size_t')
 
         self.capi_call_ifaces = {
             # name to opaque C++ scope representation
             'constructor'  : ([c_method, c_object, c_int, c_voidp],   c_object),
             'call_o'       : ([c_method, c_object, c_int, c_voidp, c_type],     c_object),
 
+            'get_methptr_getter' : ([c_scope, c_index],               c_voidp), # TODO: verify
+
+            # handling of function argument buffer
+            'allocate_function_args'   : ([c_size_t],                 c_voidp),
+            'deallocate_function_args' : ([c_voidp],                  c_void),
+            'function_arg_sizeof'      : ([],                         c_size_t),
+            'function_arg_typeoffset'  : ([],                         c_size_t),
+
+            # scope reflection information
+            'is_namespace'          : ([c_scope],                     c_int),
+            'is_enum'               : ([c_ccharp],                    c_int),
+
             # type/class reflection information
             'final_name'            : ([c_type],                      c_ccharp),
             'scoped_final_name'     : ([c_type],                      c_ccharp),
             'has_complex_hierarchy' : ([c_type],                      c_int),
             'num_bases'             : ([c_type],                      c_int),
             'base_name'             : ([c_type, c_int],               c_ccharp),
+            'is_subtype'            : ([c_type, c_type],              c_int),
+
+            'base_offset'           : ([c_type, c_type, c_object, c_int],       c_long),
 
             # method/function reflection information
+            'num_methods'           : ([c_scope],                     c_int),
+            'method_index_at'       : ([c_scope, c_int],              c_index),
+            'method_indices_from_name' : ([c_scope, c_ccharp],        c_index_array),
 
             'method_name'           : ([c_scope, c_index],            c_ccharp),
             'method_result_type'    : ([c_scope, c_index],            c_ccharp),
+            'method_num_args'       : ([c_scope, c_index],            c_int),
 
             'method_arg_type'       : ([c_scope, c_index, c_int],     c_ccharp),
             'method_arg_default'    : ([c_scope, c_index, c_int],     c_ccharp),
             'method_signature'      : ([c_scope, c_index],            c_ccharp),
 
-            'method_template_arg_name' : ([c_scope, c_index, c_index], c_ccharp),
+            'method_template_arg_name' : ([c_scope, c_index, c_index],          c_ccharp),
 
             # data member reflection information
             'datamember_name'       : ([c_scope, c_int],              c_ccharp),
         return False
     return True
 
-def call_capi(space, name, args_w):
+def call_capi(space, name, args):
     state = space.fromcache(State)
     try:
         c_call = state.capi_calls[name]
         if state.library is None:
             load_reflection_library(space)
         iface = state.capi_call_ifaces[name]
-        from pypy.module._cffi_backend.ctypefunc import W_CTypeFunc
-        cfunc = W_CTypeFunc(space, iface[0], iface[1], False)
+        cfunc = W_RCTypeFunc(space, iface[0], iface[1], False)
         c_call = state.library.load_function(cfunc, 'cppyy_'+name)
         # TODO: there must be a better way to trick the leakfinder ...
         if not objectmodel.we_are_translated():
             leakfinder.remember_free(c_call.ctype.cif_descr._obj0)
         state.capi_calls[name] = c_call
-    return c_call.call(args_w)
+    return c_call.ctype.rcall(c_call._cdata, args)
 
+def _longptr_to_int(longptr):
+    return int(rffi.cast(rffi.INTP, longptr)[0])
 
 # name to opaque C++ scope representation ------------------------------------
 def c_num_scopes(space, cppscope):
-    args_w = [space.wrap(cppscope.handle)]
-    return space.int_w(call_capi(space, 'num_scopes', args_w))
+    return call_capi(space, 'num_scopes', [_Arg(l=cppscope.handle)])[0]
 def c_scope_name(space, cppscope, iscope):
-    args_w = [space.wrap(cppscope.handle), space.wrap(iscope)]
-    return charp2str_free(space, call_capi(space, 'scope_name', args_w))
+    args = [_Arg(l=cppscope.handle), _Arg(l=iscope)]
+    return charp2str_free(space, call_capi(space, 'scope_name', args))
 
 def c_resolve_name(space, name):
-    args_w = [space.wrap(name)]
-    return charp2str_free(space, call_capi(space, 'resolve_name', args_w))
+    return charp2str_free(space, call_capi(space, 'resolve_name', [_Arg(s=name)]))
 def c_get_scope_opaque(space, name):
-    args_w = [space.wrap(name)]
-    return rffi.cast(C_SCOPE, space.int_w(call_capi(space, 'get_scope', args_w)))
+    return rffi.cast(C_SCOPE, call_capi(space, 'get_scope', [_Arg(s=name)])[0])
 def c_get_template(space, name):
-    args_w = [space.wrap(name)]
-    return rffi.cast(C_TYPE, space.int_w(call_capi(space, 'get_template', args_w)))
+    return rffi.cast(C_TYPE, call_capi(space, 'get_template', [_Arg(s=name)])[0])
 def c_actual_class(space, cppclass, cppobj):
-    args_w = [space.wrap(cppclass.handle), space.wrap(cppobj)]
-    return rffi.cast(C_TYPE, space.int_w(call_capi(space, 'actual_class', args_w)))
+    args = [_Arg(l=cppclass.handle), _Arg(l=cppobj)]
+    return rffi.cast(C_TYPE, call_capi(space, 'actual_class', args)[0])
 
 # memory management ----------------------------------------------------------
 def c_allocate(space, cppclass):
-    args_w = [space.wrap(cppclass.handle)]
-    return rffi.cast(C_OBJECT, space.int_w(call_capi(space, 'allocate', args_w)))
+    return rffi.cast(C_OBJECT, call_capi(space, 'allocate', [_Arg(l=cppclass.handle)])[0])
 def c_deallocate(space, cppclass, cppobject):
-    args_w = [space.wrap(cppclass.handle), space.wrap(cppobject)]
-    call_capi(space, 'deallocate', args_w)
+    call_capi(space, 'deallocate', [_Arg(l=cppclass.handle), _Arg(l=cppobject)])
 def c_destruct(space, cppclass, cppobject):
-    args_w = [space.wrap(cppclass.handle), space.wrap(cppobject)]
-    call_capi(space, 'destruct', args_w)
+    call_capi(space, 'destruct', [_Arg(l=cppclass.handle), _Arg(l=cppobject)])
 
 # method/function dispatching ------------------------------------------------
-def c_call_v(space, cppmethod, cppobject, nargs, args):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args))]
-    call_capi(space, 'call_v', args_w)
-# TODO: these method do not actually need unwrapping, as the excutors simply
-# wrap the values again, but the other backends expect that ...
-def c_call_b(space, cppmethod, cppobject, nargs, args):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args))]
-    return rffi.cast(rffi.UCHAR, space.int_w(call_capi(space, 'call_b', args_w)))
-def c_call_c(space, cppmethod, cppobject, nargs, args):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args))]
-    return rffi.cast(rffi.CHAR, space.str_w(call_capi(space, 'call_c', args_w)))
-def c_call_h(space, cppmethod, cppobject, nargs, args):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args))]
-    return rffi.cast(rffi.SHORT, space.int_w(call_capi(space, 'call_h', args_w)))
-def c_call_i(space, cppmethod, cppobject, nargs, args):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args))]
-    return rffi.cast(rffi.INT, space.int_w(call_capi(space, 'call_i', args_w)))
-def c_call_l(space, cppmethod, cppobject, nargs, args):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args))]
-    return rffi.cast(rffi.LONG, space.int_w(call_capi(space, 'call_l', args_w)))
-def c_call_ll(space, cppmethod, cppobject, nargs, args):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args))]
-    return rffi.cast(rffi.LONGLONG, space.int_w(call_capi(space, 'call_ll', args_w)))
-def c_call_f(space, cppmethod, cppobject, nargs, args):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args))]
-    return rffi.cast(rffi.FLOAT, space.float_w(call_capi(space, 'call_f', args_w)))
-def c_call_d(space, cppmethod, cppobject, nargs, args):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args))]
-    return rffi.cast(rffi.DOUBLE, space.float_w(call_capi(space, 'call_d', args_w)))
+def c_call_v(space, cppmethod, cppobject, nargs, cargs):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs)]
+    call_capi(space, 'call_v', args)
+def c_call_b(space, cppmethod, cppobject, nargs, cargs):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs)]
+    return rffi.cast(rffi.UCHARP, call_capi(space, 'call_b', args))[0]
+def c_call_c(space, cppmethod, cppobject, nargs, cargs):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs)]
+    return rffi.cast(rffi.CCHARP, call_capi(space, 'call_c', args))[0]
+def c_call_h(space, cppmethod, cppobject, nargs, cargs):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs)]
+    return rffi.cast(rffi.SHORTP, call_capi(space, 'call_h', args))[0]
+def c_call_i(space, cppmethod, cppobject, nargs, cargs):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs)]
+    return rffi.cast(rffi.INTP, call_capi(space, 'call_i', args))[0]
+def c_call_l(space, cppmethod, cppobject, nargs, cargs):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs)]
+    return rffi.cast(rffi.LONGP, call_capi(space, 'call_l', args))[0]
+def c_call_ll(space, cppmethod, cppobject, nargs, cargs):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs)]
+    return rffi.cast(rffi.LONGLONGP, call_capi(space, 'call_ll', args))[0]
+def c_call_f(space, cppmethod, cppobject, nargs, cargs):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs)]
+    return rffi.cast(rffi.FLOATP, call_capi(space, 'call_f', args))[0]
+def c_call_d(space, cppmethod, cppobject, nargs, cargs):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs)]
+    return rffi.cast(rffi.DOUBLEP, call_capi(space, 'call_d', args))[0]
 
-def c_call_r(space, cppmethod, cppobject, nargs, args):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args))]
-    return rffi.cast(rffi.VOIDP, space.int_w(call_capi(space, 'call_r', args_w)))
-def c_call_s(space, cppmethod, cppobject, nargs, args):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args))]
-    return call_capi(space, 'call_s', args_w)
+def c_call_r(space, cppmethod, cppobject, nargs, cargs):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs)]
+    return rffi.cast(rffi.VOIDPP, call_capi(space, 'call_r', args))[0]
+def c_call_s(space, cppmethod, cppobject, nargs, cargs):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs)]
+    return call_capi(space, 'call_s', args)
 
-def c_constructor(space, cppmethod, cppobject, nargs, args):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args))]
-    return rffi.cast(C_OBJECT, space.int_w(call_capi(space, 'constructor', args_w)))
-def c_call_o(space, cppmethod, cppobject, nargs, args, cppclass):
-    args_w = [space.wrap(cppmethod), space.wrap(cppobject),
-              space.wrap(nargs), space.wrap(rffi.cast(rffi.ULONG, args)),
-              space.wrap(cppclass.handle)]
-    return rffi.cast(C_OBJECT, space.int_w(call_capi(space, 'call_o', args_w)))
+def c_constructor(space, cppmethod, cppobject, nargs, cargs):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs)]
+    return rffi.cast(C_OBJECT, call_capi(space, 'constructor', args)[0])
+def c_call_o(space, cppmethod, cppobject, nargs, cargs, cppclass):
+    args = [_Arg(l=cppmethod), _Arg(l=cppobject), _Arg(l=nargs), _Arg(vp=cargs), _Arg(l=cppclass.handle)]
+    return rffi.cast(C_OBJECT, call_capi(space, 'call_o', args)[0])
 
-_c_get_methptr_getter = rffi.llexternal(
-    "cppyy_get_methptr_getter",
-    [C_SCOPE, C_INDEX], C_METHPTRGETTER_PTR,
-    threadsafe=ts_reflect,
-    compilation_info=backend.eci,
-    elidable_function=True)
-def c_get_methptr_getter(cppscope, index):
-    return _c_get_methptr_getter(cppscope.handle, index)
+@jit.elidable_promote()
+def c_get_methptr_getter(space, cppscope, index):
+    args = [_Arg(l=cppscope.handle), _Arg(l=index)]
+    return rffi.cast(C_METHPTRGETTER_PTR, call_capi(space, 'get_methptr_getter', args)[0])
 
 # handling of function argument buffer ---------------------------------------
-c_allocate_function_args = rffi.llexternal(
-    "cppyy_allocate_function_args",
-    [rffi.SIZE_T], rffi.VOIDP,
-    threadsafe=ts_memory,
-    compilation_info=backend.eci)
-c_deallocate_function_args = rffi.llexternal(
-    "cppyy_deallocate_function_args",
-    [rffi.VOIDP], lltype.Void,
-    threadsafe=ts_memory,
-    compilation_info=backend.eci)
-c_function_arg_sizeof = rffi.llexternal(
-    "cppyy_function_arg_sizeof",
-    [], rffi.SIZE_T,
-    threadsafe=ts_memory,
-    compilation_info=backend.eci,
-    elidable_function=True)
-c_function_arg_typeoffset = rffi.llexternal(
-    "cppyy_function_arg_typeoffset",
-    [], rffi.SIZE_T,
-    threadsafe=ts_memory,
-    compilation_info=backend.eci,
-    elidable_function=True)
+def c_allocate_function_args(space, size):
+    return rffi.cast(rffi.VOIDP, call_capi(space, 'allocate_function_args', [_Arg(l=size)])[0])
+def c_deallocate_function_args(space, cargs):
+    call_capi(space, 'deallocate_function_args', [_Arg(vp=cargs)])
+@jit.elidable_promote()
+def c_function_arg_sizeof(space):
+    return rffi.cast(rffi.SIZE_T, call_capi(space, 'function_arg_sizeof', [])[0])
+@jit.elidable_promote()
+def c_function_arg_typeoffset(space):
+    return rffi.cast(rffi.SIZE_T, call_capi(space, 'function_arg_typeoffset', [])[0])
 
 # scope reflection information -----------------------------------------------
-c_is_namespace = rffi.llexternal(
-    "cppyy_is_namespace",
-    [C_SCOPE], rffi.INT,
-    threadsafe=ts_reflect,
-    compilation_info=backend.eci)
-c_is_enum = rffi.llexternal(
-    "cppyy_is_enum",
-    [rffi.CCHARP], rffi.INT,
-    threadsafe=ts_reflect,
-    compilation_info=backend.eci)
+def c_is_namespace(space, scope):
+    return _longptr_to_int(call_capi(space, 'is_namespace', [_Arg(l=scope)]))
+def c_is_enum(space, name):
+    return _longptr_to_int(call_capi(space, 'is_enum', [_Arg(s=name)]))
 
 # type/class reflection information ------------------------------------------
 def c_final_name(space, cpptype):
-    args_w = [space.wrap(cpptype)]
-    return charp2str_free(space, call_capi(space, 'final_name', args_w))
+    return charp2str_free(space, call_capi(space, 'final_name', [_Arg(l=cpptype)]))
 def c_scoped_final_name(space, cpptype):
-    args_w = [space.wrap(cpptype)]
-    return charp2str_free(space, call_capi(space, 'scoped_final_name', args_w))
+    return charp2str_free(space, call_capi(space, 'scoped_final_name', [_Arg(l=cpptype)]))
 def c_has_complex_hierarchy(space, handle):
-    args_w = [space.wrap(handle)]
-    return space.int_w(call_capi(space, 'has_complex_hierarchy', args_w))
+    return _longptr_to_int(call_capi(space, 'has_complex_hierarchy', [_Arg(l=handle)]))
 def c_num_bases(space, cppclass):
-    args_w = [space.wrap(cppclass.handle)]
-    return space.int_w(call_capi(space, 'num_bases', args_w))
+    return _longptr_to_int(call_capi(space, 'num_bases', [_Arg(l=cppclass.handle)]))
 def c_base_name(space, cppclass, base_index):
-    args_w = [space.wrap(cppclass.handle), space.wrap(base_index)]
-    return charp2str_free(space, call_capi(space, 'base_name', args_w))
-_c_is_subtype = rffi.llexternal(
-    "cppyy_is_subtype",
-    [C_TYPE, C_TYPE], rffi.INT,
-    threadsafe=ts_reflect,
-    compilation_info=backend.eci,
-    elidable_function=True)
+    args = [_Arg(l=cppclass.handle), _Arg(l=base_index)]
+    return charp2str_free(space, call_capi(space, 'base_name', args))
 @jit.elidable_promote()
-def c_is_subtype(derived, base):
+def c_is_subtype(space, derived, base):
     if derived == base:
         return 1
-    return _c_is_subtype(derived.handle, base.handle)
+    return _longptr_to_int(call_capi(space, 'is_subtype', [_Arg(l=derived.handle), _Arg(l=base.handle)]))
 
-_c_base_offset = rffi.llexternal(
-    "cppyy_base_offset",
-    [C_TYPE, C_TYPE, C_OBJECT, rffi.INT], rffi.SIZE_T,
-    threadsafe=ts_reflect,
-    compilation_info=backend.eci,
-    elidable_function=True)
 @jit.elidable_promote()
-def c_base_offset(derived, base, address, direction):
+def _c_base_offset(space, derived_h, base_h, address, direction):
+    args = [_Arg(l=derived_h), _Arg(l=base_h), _Arg(l=address), _Arg(l=direction)]
+    return rffi.cast(rffi.SIZE_T, rffi.cast(rffi.ULONGP, call_capi(space, 'base_offset', args))[0])
+@jit.elidable_promote()
+def c_base_offset(space, derived, base, address, direction):
     if derived == base:
         return 0
-    return _c_base_offset(derived.handle, base.handle, address, direction)
-def c_base_offset1(derived_h, base, address, direction):
-    return _c_base_offset(derived_h, base.handle, address, direction)
+    return _c_base_offset(space, derived.handle, base.handle, address, direction)
+@jit.elidable_promote()
+def c_base_offset1(space, derived_h, base, address, direction):
+    return _c_base_offset(space, derived_h, base.handle, address, direction)
 
 # method/function reflection information -------------------------------------
-_c_num_methods = rffi.llexternal(
-    "cppyy_num_methods",
-    [C_SCOPE], rffi.INT,
-    threadsafe=ts_reflect,
-    compilation_info=backend.eci)
-def c_num_methods(cppscope):
-    return _c_num_methods(cppscope.handle)
-_c_method_index_at = rffi.llexternal(
-    "cppyy_method_index_at",
-    [C_SCOPE, rffi.INT], C_INDEX,
-    threadsafe=ts_reflect,
-    compilation_info=backend.eci)
-def c_method_index_at(cppscope, imethod):
-    return _c_method_index_at(cppscope.handle, imethod)
-_c_method_indices_from_name = rffi.llexternal(
-    "cppyy_method_indices_from_name",
-    [C_SCOPE, rffi.CCHARP], C_INDEX_ARRAY,
-    threadsafe=ts_reflect,
-    compilation_info=backend.eci)
+def c_num_methods(space, cppscope):
+    args = [_Arg(l=cppscope.handle)]
+    return _longptr_to_int(call_capi(space, 'num_methods', args))
+def c_method_index_at(space, cppscope, imethod):
+    args = [_Arg(l=cppscope.handle), _Arg(l=imethod)]
+    return call_capi(space, 'method_index_at', args)[0]
 def c_method_indices_from_name(space, cppscope, name):
-    indices = _c_method_indices_from_name(cppscope.handle, name)
+    args = [_Arg(l=cppscope.handle), _Arg(s=name)]
+    indices = rffi.cast(C_INDEX_ARRAY, call_capi(space, 'method_indices_from_name', args)[0])
     if not indices:
         return []
     py_indices = []
     return py_indices
 
 def c_method_name(space, cppscope, index):
-    args_w = [space.wrap(cppscope.handle), space.wrap(index)]
-    return charp2str_free(space, call_capi(space, 'method_name', args_w))
+    args = [_Arg(l=cppscope.handle), _Arg(l=index)]
+    return charp2str_free(space, call_capi(space, 'method_name', args))
 def c_method_result_type(space, cppscope, index):
-    args_w = [space.wrap(cppscope.handle), space.wrap(index)]
-    return charp2str_free(space, call_capi(space, 'method_result_type', args_w))
+    args = [_Arg(l=cppscope.handle), _Arg(l=index)]
+    return charp2str_free(space, call_capi(space, 'method_result_type', args))
 _c_method_num_args = rffi.llexternal(
     "cppyy_method_num_args",
     [C_SCOPE, C_INDEX], rffi.INT,
     threadsafe=ts_reflect,
     compilation_info=backend.eci)
 def c_method_num_args(cppscope, index):
+    args = [_Arg(l=cppscope.handle), _Arg(l=index)]
     return _c_method_num_args(cppscope.handle, index)
 _c_method_req_args = rffi.llexternal(
     "cppyy_method_req_args",
 def c_method_req_args(cppscope, index):
     return _c_method_req_args(cppscope.handle, index)
 def c_method_arg_type(space, cppscope, index, arg_index):
-    args_w = [space.wrap(cppscope.handle), space.wrap(index), space.wrap(arg_index)]
-    return charp2str_free(space, call_capi(space, 'method_arg_type', args_w))
+    args = [_Arg(l=cppscope.handle), _Arg(l=index), _Arg(l=arg_index)]
+    return charp2str_free(space, call_capi(space, 'method_arg_type', args))
 def c_method_arg_default(space, cppscope, index, arg_index):
-    args_w = [space.wrap(cppscope.handle), space.wrap(index), space.wrap(arg_index)]
-    return charp2str_free(space, call_capi(space, 'method_arg_default', args_w))
+    args = [_Arg(l=cppscope.handle), _Arg(l=index), _Arg(l=arg_index)]
+    return charp2str_free(space, call_capi(space, 'method_arg_default', args))
 def c_method_signature(space, cppscope, index):
-    args_w = [space.wrap(cppscope.handle), space.wrap(index)]
-    return charp2str_free(space, call_capi(space, 'method_signature', args_w))
+    args = [_Arg(l=cppscope.handle), _Arg(l=index)]
+    return charp2str_free(space, call_capi(space, 'method_signature', args))
 
 _c_method_is_template = rffi.llexternal(
     "cppyy_method_is_template",
     [C_SCOPE, C_INDEX], rffi.INT,
     threadsafe=ts_reflect,
     compilation_info=backend.eci)
-_c_method_template_arg_name = rffi.llexternal(
-    "cppyy_method_template_arg_name",
-    [C_SCOPE, C_INDEX, C_INDEX], rffi.CCHARP,
-    threadsafe=ts_reflect,
-    compilation_info=backend.eci)
 def c_template_args(space, cppscope, index):
     nargs = _c_method_num_template_args(cppscope.handle, index)
+    arg1 = _Arg(l=cppscope.handle)
+    arg2 = _Arg(l=index)
     args = [c_resolve_name(space, charp2str_free(space,
-                call_capi(space, 'method_template_arg_name',
-                          [space.wrap(cppscope.handle), space.wrap(index), space.wrap(iarg)])
-                                     )
+                call_capi(space, 'method_template_arg_name', [arg1, arg2, _Arg(l=iarg)]))
             ) for iarg in range(nargs)]
     return args
 
     threadsafe=ts_reflect,
     compilation_info=backend.eci)
 def c_datamember_name(space, cppscope, datamember_index):
-    args_w = [space.wrap(cppscope.handle), space.wrap(datamember_index)]
-    return charp2str_free(space, call_capi(space, 'datamember_name', args_w))
+    args = [_Arg(l=cppscope.handle), _Arg(l=datamember_index)]
+    return charp2str_free(space, call_capi(space, 'datamember_name', args))
 _c_datamember_type = rffi.llexternal(
     "cppyy_datamember_type",
     [C_SCOPE, rffi.INT], rffi.CCHARP,
     threadsafe=ts_reflect,
     compilation_info=backend.eci)
 def c_datamember_type(space, cppscope, datamember_index):
-    args_w = [space.wrap(cppscope.handle), space.wrap(datamember_index)]
-    return charp2str_free(space, call_capi(space, 'datamember_type', args_w))
+    args = [_Arg(l=cppscope.handle), _Arg(l=datamember_index)]
+    return charp2str_free(space, call_capi(space, 'datamember_type', args))
 _c_datamember_offset = rffi.llexternal(
     "cppyy_datamember_offset",
     [C_SCOPE, rffi.INT], rffi.SIZE_T,
     threadsafe=ts_helper,
     compilation_info=backend.eci)
 def c_free(space, voidp):
-    args_w = [space.wrap(rffi.cast(rffi.ULONG, voidp))]
-    call_capi(space, 'free', args_w)
+    call_capi(space, 'free', [_Arg(vp=voidp)])
 
 def charp2str_free(space, cdata):
-    charp = rffi.cast(rffi.CCHARP, cdata._cdata)
+    charp = rffi.cast(rffi.CCHARPP, cdata)[0]
     pystr = rffi.charp2str(charp)
-    voidp = rffi.cast(rffi.VOIDP, charp)
-    c_free(space, voidp)
+    c_free(space, rffi.cast(rffi.VOIDP, charp))
     return pystr
 
 c_charp2stdstring = rffi.llexternal(

File pypy/module/cppyy/converter.py

             raise OperationError(space.w_TypeError,
                                  space.wrap("raw buffer interface not supported"))
         ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset()] = 'o'
+        ba[capi.c_function_arg_typeoffset(space)] = 'o'
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         # read access, so no copy needed
         x = rffi.cast(self.c_ptrtype, address)
         x[0] = self._unwrap_object(space, w_obj)
         ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset()] = self.typecode
+        ba[capi.c_function_arg_typeoffset(space)] = self.typecode
 
 
 class VoidConverter(TypeConverter):
         arg = space.str_w(w_obj)
         x[0] = rffi.cast(rffi.LONG, rffi.str2charp(arg))
         ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset()] = 'o'
+        ba[capi.c_function_arg_typeoffset(space)] = 'o'
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = self._get_raw_address(space, w_obj, offset)
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = self._unwrap_object(space, w_obj)
         ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset()] = 'o'
+        ba[capi.c_function_arg_typeoffset(space)] = 'o'
 
     def convert_argument_libffi(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.VOIDPP, address)
         except TypeError:
             r[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
         x[0] = rffi.cast(rffi.VOIDP, call_local)
-        ba[capi.c_function_arg_typeoffset()] = 'a'
+        ba[capi.c_function_arg_typeoffset(space)] = 'a'
 
     def finalize_call(self, space, w_obj, call_local):
         r = rffi.cast(rffi.VOIDPP, call_local)
     def _unwrap_object(self, space, w_obj):
         from pypy.module.cppyy.interp_cppyy import W_CPPInstance
         if isinstance(w_obj, W_CPPInstance):
-            if capi.c_is_subtype(w_obj.cppclass, self.cppclass):
+            if capi.c_is_subtype(space, w_obj.cppclass, self.cppclass):
                 rawobject = w_obj.get_rawobject()
-                offset = capi.c_base_offset(w_obj.cppclass, self.cppclass, rawobject, 1)
+                offset = capi.c_base_offset(space, w_obj.cppclass, self.cppclass, rawobject, 1)
                 obj_address = capi.direct_ptradd(rawobject, offset)
                 return rffi.cast(capi.C_OBJECT, obj_address)
         raise OperationError(space.w_TypeError,
         x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
         address = rffi.cast(capi.C_OBJECT, address)
         ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset()] = 'o'
+        ba[capi.c_function_arg_typeoffset(space)] = 'o'
 
     def convert_argument_libffi(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = rffi.cast(rffi.VOIDP, call_local)
         address = rffi.cast(capi.C_OBJECT, address)
         ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset()] = 'o'
+        ba[capi.c_function_arg_typeoffset(space)] = 'o'
 
     def convert_argument_libffi(self, space, w_obj, address, call_local):
         # TODO: finalize_call not yet called for fast call (see interp_cppyy.py)
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = rffi.cast(rffi.VOIDP, ref)
         ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset()] = 'a'
+        ba[capi.c_function_arg_typeoffset(space)] = 'a'
 
     def convert_argument_libffi(self, space, w_obj, address, call_local):
         # TODO: free_argument not yet called for fast call (see interp_cppyy.py)
             return InstancePtrPtrConverter(space, cppclass)
         elif compound == "":
             return InstanceConverter(space, cppclass)
-    elif capi.c_is_enum(clean_name):
+    elif capi.c_is_enum(space, clean_name):
         return _converters['unsigned'](space, default)
 
     #   5) void converter, which fails on use
                 x = rffi.cast(self.c_ptrtype, address)
                 x[0] = self._unwrap_object(space, w_obj)
                 ba = rffi.cast(rffi.CCHARP, address)
-                ba[capi.c_function_arg_typeoffset()] = self.typecode
+                ba[capi.c_function_arg_typeoffset(space)] = self.typecode
         for name in names:
             _converters[name] = BasicConverter
             _converters["const "+name+"&"] = ConstRefConverter

File pypy/module/cppyy/executor.py

 class StdStringExecutor(InstancePtrExecutor):
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
-        charp_result = capi.c_call_s(space, cppmethod, cppthis, num_args, args)
-        return space.wrap(capi.charp2str_free(space, charp_result))
+        cstr_result = capi.c_call_s(space, cppmethod, cppthis, num_args, args)
+        return space.wrap(capi.charp2str_free(space, cstr_result))
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
             return InstancePtrExecutor(space, cppclass)
         elif compound == '**' or compound == '*&':
             return InstancePtrPtrExecutor(space, cppclass)
-    elif capi.c_is_enum(clean_name):
+    elif capi.c_is_enum(space, clean_name):
         return _executors['unsigned int'](space, None)
 
     # 4) additional special cases

File pypy/module/cppyy/interp_cppyy.py

     assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
     if opaque_handle:
         final_name = capi.c_final_name(space, opaque_handle)
-        if capi.c_is_namespace(opaque_handle):
+        if capi.c_is_namespace(space, opaque_handle):
             cppscope = W_CPPNamespace(space, final_name, opaque_handle)
         elif capi.c_has_complex_hierarchy(space, opaque_handle):
             cppscope = W_ComplexCPPClass(space, final_name, opaque_handle)
         # 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.scope, self.index)
+        methgetter = capi.c_get_methptr_getter(self.space, self.scope, self.index)
         if methgetter and cppthis:      # methods only for now
             cif_descr = lltype.nullptr(jit_libffi.CIF_DESCRIPTION)
             try:
 
     @jit.unroll_safe
     def prepare_arguments(self, args_w, call_local):
-        args = capi.c_allocate_function_args(len(args_w))
-        stride = capi.c_function_arg_sizeof()
+        args = capi.c_allocate_function_args(self.space, len(args_w))
+        stride = capi.c_function_arg_sizeof(self.space)
         for i in range(len(args_w)):
             conv = self.converters[i]
             w_arg = args_w[i]
                     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(self.space, rffi.cast(capi.C_OBJECT, arg_j), loc_j)
-                capi.c_deallocate_function_args(args)
+                capi.c_deallocate_function_args(self.space, args)
                 raise
         return args
 
     @jit.unroll_safe
     def finalize_call(self, args, args_w, call_local):
-        stride = capi.c_function_arg_sizeof()
+        stride = capi.c_function_arg_sizeof(self.space)
         for i in range(len(args_w)):
             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(self.space, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
-        capi.c_deallocate_function_args(args)
+        capi.c_deallocate_function_args(self.space, args)
 
     def signature(self):
         return capi.c_method_signature(self.space, self.scope, self.index)
     def _get_offset(self, cppinstance):
         if cppinstance:
             assert lltype.typeOf(cppinstance.cppclass.handle) == lltype.typeOf(self.scope.handle)
-            offset = self.offset + capi.c_base_offset(
+            offset = self.offset + capi.c_base_offset(self.space,
                 cppinstance.cppclass, self.scope, cppinstance.get_rawobject(), 1)
         else:
             offset = self.offset
     def _build_methods(self):
         assert len(self.methods) == 0
         methods_temp = {}
-        for i in range(capi.c_num_methods(self)):
-            idx = capi.c_method_index_at(self, i)
+        for i in range(capi.c_num_methods(self.space, self)):
+            idx = capi.c_method_index_at(self.space, self, i)
             pyname = helper.map_operator_name(self.space,
                 capi.c_method_name(self.space, self, idx),
                 capi.c_method_num_args(self, idx),
             sname = capi.c_scope_name(self.space, self, i)
             if sname: alldir.append(self.space.wrap(sname))
         allmeth = {}
-        for i in range(capi.c_num_methods(self)):
-            idx = capi.c_method_index_at(self, i)
+        for i in range(capi.c_num_methods(self.space, self)):
+            idx = capi.c_method_index_at(self.space, self, i)
             mname = capi.c_method_name(self.space, self, idx)
             if mname: allmeth.setdefault(mname, 0)
         for m in allmeth.keys():
 
     def get_cppthis(self, cppinstance, calling_scope):
         assert self == cppinstance.cppclass
-        offset = capi.c_base_offset(self, calling_scope, cppinstance.get_rawobject(), 1)
+        offset = capi.c_base_offset(self.space,
+                                    self, calling_scope, cppinstance.get_rawobject(), 1)
         return capi.direct_ptradd(cppinstance.get_rawobject(), offset)
 
 W_ComplexCPPClass.typedef = TypeDef(
         if actual != cppclass.handle:
             try:
                 w_pycppclass = get_pythonized_cppclass(space, actual)
-                offset = capi.c_base_offset1(actual, cppclass, rawobject, -1)
+                offset = capi.c_base_offset1(space, actual, cppclass, rawobject, -1)
                 rawobject = capi.direct_ptradd(rawobject, offset)
                 w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
                 cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
 
     # fresh creation
     w_cppinstance = space.allocate_instance(W_CPPInstance, w_pycppclass)
-    cppinstance = space.interp_w(W_CPPInstance, w_cppinstance)
+    cppinstance = space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=False)
     cppinstance.__init__(space, cppclass, rawobject, is_ref, python_owns)
     memory_regulator.register(cppinstance)
     return w_cppinstance