Commits

Philip Jenvey committed b4ea8cb Merge

merge default

Comments (0)

Files changed (25)

pypy/doc/windows.rst

 Translating PyPy with Visual Studio
 -----------------------------------
 
-We routinely test the `RPython translation toolchain`_ using Visual Studio .NET
-2005, Professional Edition, and Visual Studio .NET 2008, Express
+We routinely test the `RPython translation toolchain`_ using 
+Visual Studio 2008, Express
 Edition.  Other configurations may work as well.
 
 The translation scripts will set up the appropriate environment variables

pypy/module/cppyy/capi/__init__.py

 
 C_METHOD = _C_OPAQUE_PTR
 C_INDEX = rffi.LONG
+C_INDEX_ARRAY = rffi.LONGP
 WLAVC_INDEX = rffi.LONG
 
 C_METHPTRGETTER = lltype.FuncType([C_OBJECT], rffi.VOIDP)
     address = rffi.cast(rffi.CCHARP, ptr)
     return rffi.cast(C_OBJECT, lltype.direct_ptradd(address, offset))
 
+def exchange_address(ptr, cif_descr, index):
+    return rffi.ptradd(ptr, cif_descr.exchange_args[index])
+
 c_load_dictionary = backend.c_load_dictionary
 
 # name to opaque C++ scope representation ------------------------------------
     compilation_info=backend.eci)
 def c_method_index_at(cppscope, imethod):
     return _c_method_index_at(cppscope.handle, imethod)
-_c_method_index_from_name = rffi.llexternal(
-    "cppyy_method_index_from_name",
-    [C_SCOPE, rffi.CCHARP], C_INDEX,
+_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_method_index_from_name(cppscope, name):
-    return _c_method_index_from_name(cppscope.handle, name)
+def c_method_indices_from_name(cppscope, name):
+    indices = _c_method_indices_from_name(cppscope.handle, name)
+    if not indices:
+        return []
+    py_indices = []
+    i = 0
+    index = indices[i]
+    while index != -1:
+        i += 1
+        py_indices.append(index)
+        index = indices[i]
+    c_free(rffi.cast(rffi.VOIDP, indices))   # c_free defined below
+    return py_indices
 
 _c_method_name = rffi.llexternal(
     "cppyy_method_name",

pypy/module/cppyy/capi/cint_capi.py

     include_dirs=[incpath] + rootincpath,
     includes=["cintcwrapper.h"],
     library_dirs=rootlibpath,
-    link_extra=["-lCore", "-lCint"],
+    libraries=["Core", "Cint"],
     use_cpp_linker=True,
 )
 
 
 def c_load_dictionary(name):
     result = _c_load_dictionary(name)
-    if not result:
-        err = rdynload.dlerror()
-        raise rdynload.DLOpenError(err)
-    return libffi.CDLL(name)       # should return handle to already open file
+    # ignore result: libffi.CDLL(name) either returns a handle to the already
+    # open file, or will fail as well and produce a correctly formatted error
+    return libffi.CDLL(name)
 
 
 # CINT-specific pythonizations ===============================================
 
+def _get_string_data(space, w_obj, m1, m2 = None):
+    from pypy.module.cppyy import interp_cppyy
+    obj = space.interp_w(interp_cppyy.W_CPPInstance, w_obj)
+    w_1 = obj.space.call_method(w_obj, m1)
+    if m2 is None:
+        return w_1
+    return obj.space.call_method(w_1, m2)
+
 ### TTree --------------------------------------------------------------------
 _ttree_Branch = rffi.llexternal(
     "cppyy_ttree_Branch",
 def register_pythonizations(space):
     "NOT_RPYTHON"
 
-    ### TTree
-    _pythonizations['ttree_Branch']  = space.wrap(interp2app(ttree_Branch))
-    _pythonizations['ttree_iter']    = space.wrap(interp2app(ttree_iter))
-    _pythonizations['ttree_getattr'] = space.wrap(interp2app(ttree_getattr))
+    allfuncs = [
+
+        ### TTree
+        ttree_Branch, ttree_iter, ttree_getattr,
+    ]
+
+    for f in allfuncs:
+        _pythonizations[f.__name__] = space.wrap(interp2app(f))
+
+def _method_alias(space, w_pycppclass, m1, m2):
+    space.setattr(w_pycppclass, space.wrap(m1),
+                  space.getattr(w_pycppclass, space.wrap(m2)))
 
 # callback coming in when app-level bound classes have been created
 def pythonize(space, name, w_pycppclass):
 
-    if name == 'TFile':
-        space.setattr(w_pycppclass, space.wrap("__getattr__"),
-                      space.getattr(w_pycppclass, space.wrap("Get")))
+    if name == "TFile":
+        _method_alias(space, w_pycppclass, "__getattr__", "Get")
 
-    elif name == 'TTree':
-        space.setattr(w_pycppclass, space.wrap("_unpythonized_Branch"),
-                      space.getattr(w_pycppclass, space.wrap("Branch")))
-        space.setattr(w_pycppclass, space.wrap("Branch"), _pythonizations["ttree_Branch"])
-        space.setattr(w_pycppclass, space.wrap("__iter__"), _pythonizations["ttree_iter"])
+    elif name == "TObjString":
+        _method_alias(space, w_pycppclass, "__str__", "GetName")
+        _method_alias(space, w_pycppclass, "_cppyy_as_builtin", "GetString")
+
+    elif name == "TString":
+        _method_alias(space, w_pycppclass, "__str__", "Data")
+        _method_alias(space, w_pycppclass, "__len__", "Length")
+        _method_alias(space, w_pycppclass, "__cmp__", "CompareTo")
+        _method_alias(space, w_pycppclass, "_cppyy_as_builtin", "Data")
+
+    elif name == "TTree":
+        _method_alias(space, w_pycppclass, "_unpythonized_Branch", "Branch")
+
+        space.setattr(w_pycppclass, space.wrap("Branch"),      _pythonizations["ttree_Branch"])
+        space.setattr(w_pycppclass, space.wrap("__iter__"),    _pythonizations["ttree_iter"])
         space.setattr(w_pycppclass, space.wrap("__getattr__"), _pythonizations["ttree_getattr"])
 
     elif name[0:8] == "TVectorT":    # TVectorT<> template
-        space.setattr(w_pycppclass, space.wrap("__len__"),
-                      space.getattr(w_pycppclass, space.wrap("GetNoElements")))
+        _method_alias(space, w_pycppclass, "__len__", "GetNoElements")

pypy/module/cppyy/capi/reflex_capi.py

     include_dirs=[incpath] + rootincpath,
     includes=["reflexcwrapper.h"],
     library_dirs=rootlibpath,
-    link_extra=["-lReflex"],
+    libraries=["Reflex"],
     use_cpp_linker=True,
 )
 

pypy/module/cppyy/converter.py

 
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rlib.rarithmetic import r_singlefloat
-from pypy.rlib import libffi, clibffi, rfloat
+from pypy.rlib import jit_libffi, rfloat
 
 from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
 from pypy.module._rawffi.array import W_Array
 
 
 class TypeConverter(object):
-    _immutable_ = True
-    libffitype = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+    _immutable_fields_ = ['libffitype', 'uses_local', 'name']
+
+    libffitype = lltype.nullptr(jit_libffi.FFI_TYPE_P.TO)
     uses_local = False
-
     name = ""
 
     def __init__(self, space, extra):
     def convert_argument(self, space, w_obj, address, call_local):
         self._is_abstract(space)
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
-    def default_argument_libffi(self, space, argchain):
+    def default_argument_libffi(self, space, address):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
 
 class ArrayTypeConverterMixin(object):
     _mixin_ = True
-    _immutable_ = True
+    _immutable_fields_ = ['libffitype', 'size']
+
+    libffitype = jit_libffi.types.pointer
 
     def __init__(self, space, array_size):
         if array_size <= 0:
 
 class PtrTypeConverterMixin(object):
     _mixin_ = True
-    _immutable_ = True
+    _immutable_fields_ = ['libffitype', 'size']
+
+    libffitype = jit_libffi.types.pointer
 
     def __init__(self, space, array_size):
         self.size = sys.maxint
         if w_tc is not None and space.str_w(w_tc) != self.typecode:
             msg = "expected %s pointer type, but received %s" % (self.typecode, space.str_w(w_tc))
             raise OperationError(space.w_TypeError, space.wrap(msg))
-        x = rffi.cast(rffi.LONGP, address)
+        x = rffi.cast(rffi.VOIDPP, address)
         try:
-            x[0] = rffi.cast(rffi.LONG, get_rawbuffer(space, w_obj))
+            x[0] = rffi.cast(rffi.VOIDP, get_rawbuffer(space, w_obj))
         except TypeError:
             raise OperationError(space.w_TypeError,
                                  space.wrap("raw buffer interface not supported"))
 
 class NumericTypeConverterMixin(object):
     _mixin_ = True
-    _immutable_ = True
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
-        argchain.arg(self._unwrap_object(space, w_obj))
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self._unwrap_object(space, w_obj)
 
-    def default_argument_libffi(self, space, argchain):
-        argchain.arg(self.default)
+    def default_argument_libffi(self, space, address):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self.default
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = self._get_raw_address(space, w_obj, offset)
 
 class ConstRefNumericTypeConverterMixin(NumericTypeConverterMixin):
     _mixin_ = True
-    _immutable_ = True
+    _immutable_fields_ = ['uses_local']
+
     uses_local = True
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
         assert rffi.sizeof(self.c_type) <= 2*rffi.sizeof(rffi.VOIDP)  # see interp_cppyy.py
         obj = self._unwrap_object(space, w_obj)
         typed_buf = rffi.cast(self.c_ptrtype, call_local)
         typed_buf[0] = obj
-        argchain.arg(call_local)
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = call_local
 
 class IntTypeConverterMixin(NumericTypeConverterMixin):
     _mixin_ = True
-    _immutable_ = True
 
     def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(self.c_ptrtype, address)
 
 class FloatTypeConverterMixin(NumericTypeConverterMixin):
     _mixin_ = True
-    _immutable_ = True
 
     def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(self.c_ptrtype, address)
 
 
 class VoidConverter(TypeConverter):
-    _immutable_ = True
-    libffitype = libffi.types.void
+    _immutable_fields_ = ['libffitype', 'name']
+
+    libffitype = jit_libffi.types.void
 
     def __init__(self, space, name):
         self.name = name
 
 
 class BoolConverter(ffitypes.typeid(bool), TypeConverter):
-    _immutable_ = True
-
     def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.LONGP, address)
         x[0] = self._unwrap_object(space, w_obj)
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
-        argchain.arg(self._unwrap_object(space, w_obj))
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.LONGP, address)
+        x[0] = self._unwrap_object(space, w_obj)
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
             address[0] = '\x00'
 
 class CharConverter(ffitypes.typeid(rffi.CHAR), TypeConverter):
-    _immutable_ = True
-
     def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.CCHARP, address)
         x[0] = self._unwrap_object(space, w_obj)
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
-        argchain.arg(self._unwrap_object(space, w_obj))
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self._unwrap_object(space, w_obj)
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
         address[0] = self._unwrap_object(space, w_value)
 
 class FloatConverter(ffitypes.typeid(rffi.FLOAT), FloatTypeConverterMixin, TypeConverter):
-    _immutable_ = True
+    _immutable_fields_ = ['default']
 
     def __init__(self, space, default):
         if default:
         return space.wrap(float(rffiptr[0]))
 
 class ConstFloatRefConverter(FloatConverter):
-    _immutable_ = True
-    libffitype = libffi.types.pointer
+    _immutable_fields_ = ['libffitype', 'typecode']
+
+    libffitype = jit_libffi.types.pointer
     typecode = 'F'
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
 class DoubleConverter(ffitypes.typeid(rffi.DOUBLE), FloatTypeConverterMixin, TypeConverter):
-    _immutable_ = True
+    _immutable_fields_ = ['default']
 
     def __init__(self, space, default):
         if default:
             self.default = rffi.cast(self.c_type, 0.)
 
 class ConstDoubleRefConverter(ConstRefNumericTypeConverterMixin, DoubleConverter):
-    _immutable_ = True
-    libffitype = libffi.types.pointer
+    _immutable_fields_ = ['libffitype', 'typecode']
+
+    libffitype = jit_libffi.types.pointer
     typecode = 'D'
 
 
 class CStringConverter(TypeConverter):
-    _immutable_ = True
-
     def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.LONGP, address)
         arg = space.str_w(w_obj)
 
 
 class VoidPtrConverter(TypeConverter):
-    _immutable_ = True
+    _immutable_fields_ = ['libffitype']
+
+    libffitype = jit_libffi.types.pointer
+
+    def _unwrap_object(self, space, w_obj):
+        try:
+            obj = get_rawbuffer(space, w_obj)
+        except TypeError:
+            obj = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+        return obj
 
     def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = self._unwrap_object(space, w_obj)
         ba = rffi.cast(rffi.CCHARP, address)
-        try:
-            x[0] = get_rawbuffer(space, w_obj)
-        except TypeError:
-            x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
         ba[capi.c_function_arg_typeoffset()] = 'o'
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
-        argchain.arg(get_rawobject(space, w_obj))
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = self._unwrap_object(space, w_obj)
 
 class VoidPtrPtrConverter(TypeConverter):
-    _immutable_ = True
+    _immutable_fields_ = ['uses_local']
+
     uses_local = True
 
     def convert_argument(self, space, w_obj, address, call_local):
             pass             # no set on buffer/array/None
 
 class VoidPtrRefConverter(VoidPtrPtrConverter):
-    _immutable_ = True
+    _immutable_fields_ = ['uses_local']
     uses_local = True
 
 class InstancePtrConverter(TypeConverter):
-    _immutable_ = True
+    _immutable_fields_ = ['libffitype', 'cppclass']
+
+    libffitype  = jit_libffi.types.pointer
 
     def __init__(self, space, cppclass):
         from pypy.module.cppyy.interp_cppyy import W_CPPClass
         ba = rffi.cast(rffi.CCHARP, address)
         ba[capi.c_function_arg_typeoffset()] = 'o'
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
-        argchain.arg(self._unwrap_object(space, w_obj))
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
         address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
 
 class InstanceConverter(InstancePtrConverter):
-    _immutable_ = True
+
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible       # TODO: by-value is a jit_libffi special case
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
         self._is_abstract(space)
 
 class InstancePtrPtrConverter(InstancePtrConverter):
-    _immutable_ = True
+    _immutable_fields_ = ['uses_local']
+
     uses_local = True
 
     def convert_argument(self, space, w_obj, address, call_local):
         ba = rffi.cast(rffi.CCHARP, address)
         ba[capi.c_function_arg_typeoffset()] = '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)
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         self._is_abstract(space)
 
 
 
 class StdStringConverter(InstanceConverter):
-    _immutable_ = True
+    _immutable_fields_ = ['cppclass']
 
     def __init__(self, space, extra):
         from pypy.module.cppyy import interp_cppyy
         capi.c_free_stdstring(rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
 
 class StdStringRefConverter(InstancePtrConverter):
-    _immutable_ = True
+    _immutable_fields_ = ['cppclass']
 
     def __init__(self, space, extra):
         from pypy.module.cppyy import interp_cppyy
 
 
 class PyObjectConverter(TypeConverter):
-    _immutable_ = True
+    _immutable_fields_ = ['libffitype']
+
+    libffitype = jit_libffi.types.pointer
 
     def convert_argument(self, space, w_obj, address, call_local):
         if hasattr(space, "fake"):
         ba = rffi.cast(rffi.CCHARP, address)
         ba[capi.c_function_arg_typeoffset()] = 'a'
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
-        if hasattr(space, "fake"):
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        # TODO: free_argument not yet called for fast call (see interp_cppyy.py)
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+        # proposed implementation:
+        """if hasattr(space, "fake"):
             raise NotImplementedError
         space.getbuiltinmodule("cpyext")
         from pypy.module.cpyext.pyobject import make_ref
         ref = make_ref(space, w_obj)
-        argchain.arg(rffi.cast(rffi.VOIDP, ref))
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, ref)"""
 
     def free_argument(self, space, arg, call_local):
         if hasattr(space, "fake"):
                 self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
         class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
             _immutable_ = True
-            libffitype = libffi.types.pointer
+            libffitype = jit_libffi.types.pointer
         for name in names:
             _converters[name] = BasicConverter
             _converters["const "+name+"&"] = ConstRefConverter
                 self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
         class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
             _immutable_ = True
-            libffitype = libffi.types.pointer
+            libffitype = jit_libffi.types.pointer
             typecode = 'r'
             def convert_argument(self, space, w_obj, address, call_local):
                 x = rffi.cast(self.c_ptrtype, address)
                 self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
         class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
             _immutable_ = True
-            libffitype = libffi.types.pointer
+            libffitype = jit_libffi.types.pointer
         for name in names:
             _converters[name] = BasicConverter
             _converters["const "+name+"&"] = ConstRefConverter
 
     for tcode, tsize, names in array_info:
         class ArrayConverter(ArrayTypeConverterMixin, TypeConverter):
-            _immutable_ = True
             typecode = tcode
             typesize = tsize
         class PtrConverter(PtrTypeConverterMixin, TypeConverter):
-            _immutable_ = True
             typecode = tcode
             typesize = tsize
         for name in names:
     for c_type, alias in aliases:
         _converters[alias] = _converters[c_type]
 _add_aliased_converters()
-

pypy/module/cppyy/executor.py

 from pypy.interpreter.error import OperationError
 
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.rlib import libffi, clibffi
+from pypy.rlib import jit_libffi
 
 from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
 from pypy.module._rawffi.array import W_Array, W_ArrayInstance
 # exact match for the qualified type.
 
 
-NULL = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+NULL = lltype.nullptr(jit_libffi.FFI_TYPE_P.TO)
 
 class FunctionExecutor(object):
-    _immutable_ = True
+    _immutable_fields_ = ['libffitype']
+
     libffitype = NULL
 
     def __init__(self, space, extra):
         raise OperationError(space.w_TypeError,
                              space.wrap('return type not available or supported'))
 
-    def execute_libffi(self, space, libffifunc, argchain):
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
 
 class PtrTypeExecutor(FunctionExecutor):
-    _immutable_ = True
+    _immutable_fields_ = ['libffitype', 'typecode']
+
+    libffitype = jit_libffi.types.pointer
     typecode = 'P'
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
 
 
 class VoidExecutor(FunctionExecutor):
-    _immutable_ = True
-    libffitype = libffi.types.void
+    _immutable_fields_ = ['libffitype']
+
+    libffitype = jit_libffi.types.void
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
         capi.c_call_v(cppmethod, cppthis, num_args, args)
         return space.w_None
 
-    def execute_libffi(self, space, libffifunc, argchain):
-        libffifunc.call(argchain, lltype.Void)
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
+        jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
         return space.w_None
 
 
 class NumericExecutorMixin(object):
     _mixin_ = True
-    _immutable_ = True
 
     def _wrap_object(self, space, obj):
         return space.wrap(obj)
         result = self.c_stubcall(cppmethod, cppthis, num_args, args)
         return self._wrap_object(space, rffi.cast(self.c_type, result))
 
-    def execute_libffi(self, space, libffifunc, argchain):
-        result = libffifunc.call(argchain, self.c_type)
-        return self._wrap_object(space, result)
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
+        data = rffi.ptradd(buffer, cif_descr.exchange_args[1])
+        jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
+        result = rffi.ptradd(buffer, cif_descr.exchange_result)
+        return self._wrap_object(space, rffi.cast(self.c_ptrtype, result)[0])
 
 class NumericRefExecutorMixin(object):
     _mixin_ = True
-    _immutable_ = True
 
     def __init__(self, space, extra):
         FunctionExecutor.__init__(self, space, extra)
         result = capi.c_call_r(cppmethod, cppthis, num_args, args)
         return self._wrap_reference(space, rffi.cast(self.c_ptrtype, result))
 
-    def execute_libffi(self, space, libffifunc, argchain):
-        result = libffifunc.call(argchain, self.c_ptrtype)
-        return self._wrap_reference(space, result)
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
+        jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
+        result = rffi.ptradd(buffer, cif_descr.exchange_result)
+        return self._wrap_reference(space,
+            rffi.cast(self.c_ptrtype, rffi.cast(rffi.VOIDPP, result)[0]))
 
 
 class CStringExecutor(FunctionExecutor):
-    _immutable_ = True
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
         lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
 
 
 class ConstructorExecutor(VoidExecutor):
-    _immutable_ = True
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
         capi.c_constructor(cppmethod, cppthis, num_args, args)
 
 
 class InstancePtrExecutor(FunctionExecutor):
-    _immutable_ = True
-    libffitype = libffi.types.pointer
+    _immutable_fields_ = ['libffitype', 'cppclass']
+
+    libffitype = jit_libffi.types.pointer
 
     def __init__(self, space, cppclass):
         FunctionExecutor.__init__(self, space, cppclass)
         return interp_cppyy.wrap_cppobject(
             space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
 
-    def execute_libffi(self, space, libffifunc, argchain):
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
+        jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
+        result = rffi.ptradd(buffer, cif_descr.exchange_result)
         from pypy.module.cppyy import interp_cppyy
-        ptr_result = rffi.cast(capi.C_OBJECT, libffifunc.call(argchain, rffi.VOIDP))
+        ptr_result = rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, result)[0])
         return interp_cppyy.wrap_cppobject(
             space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
 
 class InstancePtrPtrExecutor(InstancePtrExecutor):
-    _immutable_ = True
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
         from pypy.module.cppyy import interp_cppyy
         return interp_cppyy.wrap_cppobject(
             space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
 
-    def execute_libffi(self, space, libffifunc, argchain):
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
 class InstanceExecutor(InstancePtrExecutor):
-    _immutable_ = True
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
         from pypy.module.cppyy import interp_cppyy
         return interp_cppyy.wrap_cppobject(
             space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=True)
 
-    def execute_libffi(self, space, libffifunc, argchain):
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
 
 class StdStringExecutor(InstancePtrExecutor):
-    _immutable_ = True
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
         charp_result = capi.c_call_s(cppmethod, cppthis, num_args, args)
         return space.wrap(capi.charp2str_free(charp_result))
 
-    def execute_libffi(self, space, libffifunc, argchain):
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
 
 class PyObjectExecutor(PtrTypeExecutor):
-    _immutable_ = True
 
     def wrap_result(self, space, lresult):
         space.getbuiltinmodule("cpyext")
         lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
         return self.wrap_result(space, lresult)
 
-    def execute_libffi(self, space, libffifunc, argchain):
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         if hasattr(space, "fake"):
             raise NotImplementedError
-        lresult = libffifunc.call(argchain, rffi.LONG)
-        return self.wrap_result(space, lresult)
+        jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
+        result = rffi.ptradd(buffer, cif_descr.exchange_result)
+        return self.wrap_result(space, rffi.cast(rffi.LONGP, result)[0])
 
 
 _executors = {}
             _immutable_ = True
             c_stubcall  = staticmethod(stub)
         class BasicRefExecutor(ffitypes.typeid(c_type), NumericRefExecutorMixin, FunctionExecutor):
-            _immutable_ = True
-            libffitype = libffi.types.pointer
+            _immutable_fields_ = ['libffitype']
+            libffitype = jit_libffi.types.pointer
         for name in names:
             _executors[name]              = BasicExecutor
             _executors[name+'&']          = BasicRefExecutor
 
     for tcode, names in ptr_info:
         class PtrExecutor(PtrTypeExecutor):
-            _immutable_ = True
+            _immutable_fields_ = ['typecode']
             typecode = tcode
         for name in names:
             _executors[name+'*'] = PtrExecutor

pypy/module/cppyy/ffitypes.py

 
 from pypy.rpython.lltypesystem import rffi
 from pypy.rlib.rarithmetic import r_singlefloat
-from pypy.rlib import libffi, rfloat
+from pypy.rlib import jit_libffi, rfloat
 
 # Mixins to share between converter and executor classes (in converter.py and
 # executor.py, respectively). Basically these mixins allow grouping of the
-# sets of libffi, rffi, and different space unwrapping calls. To get the right
-# mixin, a non-RPython function typeid() is used.
+# sets of jit_libffi, rffi, and different space unwrapping calls. To get the
+# right mixin, a non-RPython function typeid() is used.
 
 
 class BoolTypeMixin(object):
     _mixin_     = True
-    _immutable_ = True
-    libffitype  = libffi.types.uchar
+    _immutable_fields_ = ['libffitype', 'c_type', 'c_ptrtype']
+
+    libffitype  = jit_libffi.types.uchar
     c_type      = rffi.UCHAR
     c_ptrtype   = rffi.UCHARP
 
 
 class CharTypeMixin(object):
     _mixin_     = True
-    _immutable_ = True
-    libffitype  = libffi.types.schar
+    _immutable_fields_ = ['libffitype', 'c_type', 'c_ptrtype']
+
+    libffitype  = jit_libffi.types.schar
     c_type      = rffi.CHAR
     c_ptrtype   = rffi.CCHARP           # there's no such thing as rffi.CHARP
 
 
 class ShortTypeMixin(object):
     _mixin_     = True
-    _immutable_ = True
-    libffitype  = libffi.types.sshort
+    _immutable_fields_ = ['libffitype', 'c_type', 'c_ptrtype']
+
+    libffitype  = jit_libffi.types.sshort
     c_type      = rffi.SHORT
     c_ptrtype   = rffi.SHORTP
 
 
 class UShortTypeMixin(object):
     _mixin_     = True
-    _immutable_ = True
-    libffitype  = libffi.types.ushort
+    _immutable_fields_ = ['libffitype', 'c_type', 'c_ptrtype']
+
+    libffitype  = jit_libffi.types.ushort
     c_type      = rffi.USHORT
     c_ptrtype   = rffi.USHORTP
 
 
 class IntTypeMixin(object):
     _mixin_     = True
-    _immutable_ = True
-    libffitype  = libffi.types.sint
+    _immutable_fields_ = ['libffitype', 'c_type', 'c_ptrtype']
+
+    libffitype  = jit_libffi.types.sint
     c_type      = rffi.INT
     c_ptrtype   = rffi.INTP
 
 
 class UIntTypeMixin(object):
     _mixin_     = True
-    _immutable_ = True
-    libffitype  = libffi.types.uint
+    _immutable_fields_ = ['libffitype', 'c_type', 'c_ptrtype']
+
+    libffitype  = jit_libffi.types.uint
     c_type      = rffi.UINT
     c_ptrtype   = rffi.UINTP
 
 
 class LongTypeMixin(object):
     _mixin_     = True
-    _immutable_ = True
-    libffitype = libffi.types.slong
-    c_type     =  rffi.LONG
+    _immutable_fields_ = ['libffitype', 'c_type', 'c_ptrtype']
+
+    libffitype  = jit_libffi.types.slong
+    c_type      =  rffi.LONG
     c_ptrtype   = rffi.LONGP
 
     def _unwrap_object(self, space, w_obj):
 
 class ULongTypeMixin(object):
     _mixin_     = True
-    _immutable_ = True
-    libffitype = libffi.types.ulong
-    c_type     = rffi.ULONG
-    c_ptrtype  = rffi.ULONGP
+    _immutable_fields_ = ['libffitype', 'c_type', 'c_ptrtype']
+
+    libffitype  = jit_libffi.types.ulong
+    c_type      = rffi.ULONG
+    c_ptrtype   = rffi.ULONGP
 
     def _unwrap_object(self, space, w_obj):
         return space.uint_w(w_obj)
 
 class LongLongTypeMixin(object):
     _mixin_     = True
-    _immutable_ = True
-    libffitype  = libffi.types.sint64
+    _immutable_fields_ = ['libffitype', 'c_type', 'c_ptrtype']
+
+    libffitype  = jit_libffi.types.sint64
     c_type      = rffi.LONGLONG
     c_ptrtype   = rffi.LONGLONGP
 
 
 class ULongLongTypeMixin(object):
     _mixin_     = True
-    _immutable_ = True
-    libffitype = libffi.types.uint64
-    c_type     = rffi.ULONGLONG
-    c_ptrtype  = rffi.ULONGLONGP
+    _immutable_fields_ = ['libffitype', 'c_type', 'c_ptrtype']
+
+    libffitype  = jit_libffi.types.uint64
+    c_type      = rffi.ULONGLONG
+    c_ptrtype   = rffi.ULONGLONGP
 
     def _unwrap_object(self, space, w_obj):
         return space.r_ulonglong_w(w_obj)
 
 class FloatTypeMixin(object):
     _mixin_     = True
-    _immutable_ = True
-    libffitype  = libffi.types.float
+    _immutable_fields_ = ['libffitype', 'c_type', 'c_ptrtype', 'typecode']
+
+    libffitype  = jit_libffi.types.float
     c_type      = rffi.FLOAT
     c_ptrtype   = rffi.FLOATP
     typecode    = 'f'
 
 class DoubleTypeMixin(object):
     _mixin_     = True
-    _immutable_ = True
-    libffitype  = libffi.types.double
+    _immutable_fields_ = ['libffitype', 'c_type', 'c_ptrtype', 'typecode']
+
+    libffitype  = jit_libffi.types.double
     c_type      = rffi.DOUBLE
     c_ptrtype   = rffi.DOUBLEP
     typecode    = 'd'

pypy/module/cppyy/include/capi.h

     /* method/function reflection information --------------------------------- */
     int cppyy_num_methods(cppyy_scope_t scope);
     cppyy_index_t cppyy_method_index_at(cppyy_scope_t scope, int imeth);
-    cppyy_index_t cppyy_method_index_from_name(cppyy_scope_t scope, const char* name);
+    cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const char* name);
 
     char* cppyy_method_name(cppyy_scope_t scope, cppyy_index_t idx);
     char* cppyy_method_result_type(cppyy_scope_t scope, cppyy_index_t idx);

pypy/module/cppyy/interp_cppyy.py

 from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
 from pypy.interpreter.baseobjspace import Wrappable, W_Root
 
-from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rpython.lltypesystem import rffi, lltype, llmemory
 
-from pypy.rlib import libffi, rdynload, rweakref
-from pypy.rlib import jit, debug, objectmodel
+from pypy.rlib import jit, rdynload, rweakref
+from pypy.rlib import jit_libffi, clibffi
+from pypy.rlib.objectmodel import we_are_translated
 
 from pypy.module.cppyy import converter, executor, helper
 
     try:
         cdll = capi.c_load_dictionary(name)
     except rdynload.DLOpenError, e:
-        raise OperationError(space.w_RuntimeError, space.wrap(str(e)))
+        raise OperationError(space.w_RuntimeError, space.wrap(str(e.msg)))
     return W_CPPLibrary(space, cdll)
 
 class State(object):
     function if available, makes the call, and returns the wrapped result. It
     also takes care of offset casting and recycling of known objects through
     the memory_regulator."""
+
+    _attrs_ = ['space', 'scope', 'index', 'cppmethod', 'arg_defs', 'args_required',
+               'args_expected', 'converters', 'executor', '_funcaddr', 'cif_descr',
+               'uses_local']
     _immutable_ = True
-    
+
     def __init__(self, space, containing_scope, method_index, arg_defs, args_required):
         self.space = space
         self.scope = containing_scope
         # the method is actually used.
         self.converters = None
         self.executor = None
-        self._libffifunc = None
+        self.cif_descr = lltype.nullptr(jit_libffi.CIF_DESCRIPTION)
+        self._funcaddr = lltype.nullptr(rffi.VOIDP.TO)
+        self.uses_local = False
 
     def _address_from_local_buffer(self, call_local, idx):
         if not call_local:
 
     @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)
 
         # initial setup of converters, executors, and libffi (if available)
         if self.converters is None:
-            self._setup(cppthis)
+            try:
+                self._setup(cppthis)
+            except Exception, e:
+                pass
 
         # 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]:
+        if self.uses_local:
             call_local = lltype.malloc(rffi.VOIDP.TO, 2*len(args_w), flavor='raw')
         else:
             call_local = lltype.nullptr(rffi.VOIDP.TO)
 
         try:
             # attempt to call directly through ffi chain
-            if self._libffifunc:
+            if self._funcaddr:
                 try:
                     return self.do_fast_call(cppthis, args_w, call_local)
                 except FastCallNotPossible:
 
     @jit.unroll_safe
     def do_fast_call(self, cppthis, args_w, call_local):
-        jit.promote(self)
-        argchain = libffi.ArgChain()
-        argchain.arg(cppthis)
-        i = len(self.arg_defs)
-        for i in range(len(args_w)):
-            conv = self.converters[i]
-            w_arg = args_w[i]
-            conv.convert_argument_libffi(self.space, w_arg, argchain, call_local)
-        for j in range(i+1, len(self.arg_defs)):
-            conv = self.converters[j]
-            conv.default_argument_libffi(self.space, argchain)
-        return self.executor.execute_libffi(self.space, self._libffifunc, argchain)
+        if self.cif_descr is None:
+            raise FastCallNotPossible
+        cif_descr = self.cif_descr
+        buffer = lltype.malloc(rffi.CCHARP.TO, cif_descr.exchange_size, flavor='raw')
+        try:
+            # this pointer
+            data = capi.exchange_address(buffer, cif_descr, 0)
+            x = rffi.cast(rffi.LONGP, data)       # LONGP needed for test_zjit.py
+            x[0] = rffi.cast(rffi.LONG, cppthis)
+
+            # other arguments and defaults
+            i = len(self.arg_defs) + 1
+            for i in range(len(args_w)):
+                conv = self.converters[i]
+                w_arg = args_w[i]
+                data = capi.exchange_address(buffer, cif_descr, i+1)
+                conv.convert_argument_libffi(self.space, w_arg, data, call_local)
+            for j in range(i+1, len(self.arg_defs)):
+                conv = self.converters[j]
+                data = capi.exchange_address(buffer, cif_descr, j+1)
+                conv.default_argument_libffi(self.space, data)
+
+            w_res = self.executor.execute_libffi(
+                self.space, cif_descr, self._funcaddr, buffer)
+        finally:
+            lltype.free(buffer, flavor='raw')
+        return w_res
 
     def _setup(self, cppthis):
         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))
 
+        for conv in self.converters:
+            if conv.uses_local:
+                self.uses_local = True
+                break
+
         # 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)
         if methgetter and cppthis:      # methods only for now
-            funcptr = methgetter(rffi.cast(capi.C_OBJECT, cppthis))
-            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",
-                                         [libffi.types.pointer] + argtypes_libffi,
-                                         self.executor.libffitype, funcptr)
-                self._libffifunc = libffifunc
+            cif_descr = lltype.nullptr(jit_libffi.CIF_DESCRIPTION)
+            try:
+                funcaddr = methgetter(rffi.cast(capi.C_OBJECT, cppthis))
+                self._funcaddr = rffi.cast(rffi.VOIDP, funcaddr)
+
+                nargs = self.args_expected + 1                   # +1: cppthis
+
+                # memory block for CIF description (note: not tracked as the life
+                # time of methods is normally the duration of the application)
+                size = llmemory.sizeof(jit_libffi.CIF_DESCRIPTION, nargs)
+
+                # allocate the buffer
+                cif_descr = lltype.malloc(jit_libffi.CIF_DESCRIPTION_P.TO,
+                                          llmemory.raw_malloc_usage(size),
+                                          flavor='raw', track_allocation=False)
+
+                # array of 'ffi_type*' values, one per argument
+                size = rffi.sizeof(jit_libffi.FFI_TYPE_P) * nargs
+                atypes = lltype.malloc(rffi.CCHARP.TO, llmemory.raw_malloc_usage(size),
+                                       flavor='raw', track_allocation=False)
+                cif_descr.atypes = rffi.cast(jit_libffi.FFI_TYPE_PP, atypes)
+
+                # argument type specification
+                cif_descr.atypes[0] = jit_libffi.types.pointer   # cppthis
+                for i, conv in enumerate(self.converters):
+                    if not conv.libffitype:
+                        raise FastCallNotPossible
+                    cif_descr.atypes[i+1] = conv.libffitype
+
+                # result type specification
+                cif_descr.rtype = self.executor.libffitype
+
+                # exchange ---
+
+                # first, enough room for an array of 'nargs' pointers
+                exchange_offset = rffi.sizeof(rffi.CCHARP) * nargs
+                exchange_offset = (exchange_offset + 7) & ~7     # alignment
+                cif_descr.exchange_result = exchange_offset
+                cif_descr.exchange_result_libffi = exchange_offset
+
+                # TODO: left this out while testing (see ctypefunc.py)
+                # 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.
+
+                # then enough room for the result, rounded up to sizeof(ffi_arg)
+                exchange_offset += max(rffi.getintfield(cif_descr.rtype, 'c_size'),
+                                       jit_libffi.SIZE_OF_FFI_ARG)
+
+                # loop over args
+                for i in range(nargs):
+                    exchange_offset = (exchange_offset + 7) & ~7 # alignment
+                    cif_descr.exchange_args[i] = exchange_offset
+                    exchange_offset += rffi.getintfield(cif_descr.atypes[i], 'c_size')
+
+                # store the exchange data size
+                cif_descr.exchange_size = exchange_offset
+
+                # --- exchange
+
+                # extra
+                cif_descr.abi = clibffi.FFI_DEFAULT_ABI
+                cif_descr.nargs = self.args_expected + 1         # +1: cppthis
+
+                res = jit_libffi.jit_ffi_prep_cif(cif_descr)
+                if res != clibffi.FFI_OK:
+                    raise FastCallNotPossible
+
+            except Exception, e:
+                if cif_descr:
+                    lltype.free(cif_descr.atypes, flavor='raw', track_allocation=False)
+                    lltype.free(cif_descr, flavor='raw', track_allocation=False)
+                cif_descr = lltype.nullptr(jit_libffi.CIF_DESCRIPTION)
+                self._funcaddr = lltype.nullptr(rffi.VOIDP.TO)
+
+            self.cif_descr = cif_descr
 
     @jit.unroll_safe
     def prepare_arguments(self, args_w, call_local):
-        jit.promote(self)
         args = capi.c_allocate_function_args(len(args_w))
         stride = capi.c_function_arg_sizeof()
         for i in range(len(args_w)):
     def signature(self):
         return capi.c_method_signature(self.scope, self.index)
 
+    def __del__(self):
+        if self.cif_descr:
+            lltype.free(self.cif_descr.atypes, flavor='raw')
+            lltype.free(self.cif_descr, flavor='raw')
+
     def __repr__(self):
         return "CPPMethod: %s" % self.signature()
 
     """Global (namespaced) function dispatcher. For now, the base class has
     all the needed functionality, by allowing the C++ this pointer to be null
     in the call. An optimization is expected there, however."""
+
     _immutable_ = True
 
     def __repr__(self):
     """Method dispatcher that constructs new objects. In addition to the call,
     it allocates memory for the newly constructed object and sets ownership
     to Python."""
+
     _immutable_ = True
 
     def call(self, cppthis, args_w):
     """Method dispatcher specific to Python's __setitem__ mapped onto C++'s
     operator[](int). The former function takes an extra argument to assign to
     the return type of the latter."""
+
     _immutable_ = True
 
     def call(self, cppthis, args_w):
     """Dispatcher that is actually available at the app-level: it is a
     collection of (possibly) overloaded methods or functions. It calls these
     in order and deals with error handling and reporting."""
-    _immutable_ = True
+
+    _attrs_ = ['space', 'scope', 'functions']
+    _immutable_fields_ = ['scope', 'functions[*]']
 
     def __init__(self, space, containing_scope, functions):
         self.space = space
         self.scope = containing_scope
+        from pypy.rlib import debug
         self.functions = debug.make_sure_not_resized(functions)
 
+    @jit.elidable_promote()
     def is_static(self):
-        return self.space.wrap(isinstance(self.functions[0], CPPFunction))
+        if isinstance(self.functions[0], CPPFunction):
+            return self.space.w_True
+        return self.space.w_False
 
     @jit.unroll_safe
     @unwrap_spec(args_w='args_w')
 
 
 class W_CPPDataMember(Wrappable):
-    _immutable_ = True
+    _attrs_ = ['space', 'scope', 'converter', 'offset', '_is_static']
+    _immutable_fields = ['scope', 'converter', 'offset', '_is_static']
 
     def __init__(self, space, containing_scope, type_name, offset, is_static):
         self.space = space
 
 
 class W_CPPScope(Wrappable):
-    _immutable_ = True
-    _immutable_fields_ = ["methods[*]", "datamembers[*]"]
+    _attrs_ = ['space', 'name', 'handle', 'methods', 'datamembers']
+    _immutable_fields_ = ['kind', 'name']
 
     kind = "scope"
 
 # classes for inheritance. Both are python classes, though, and refactoring
 # may be in order at some point.
 class W_CPPNamespace(W_CPPScope):
-    _immutable_ = True
+    _immutable_fields_ = ['kind']
+
     kind = "namespace"
 
     def _make_cppfunction(self, pyname, index):
                 self._make_datamember(datamember_name, i)
 
     def find_overload(self, meth_name):
-        # TODO: collect all overloads, not just the non-overloaded version
-        meth_idx = capi.c_method_index_from_name(self, meth_name)
-        if meth_idx == -1:
+        indices = capi.c_method_indices_from_name(self, meth_name)
+        if not indices:
             raise self.missing_attribute_error(meth_name)
-        cppfunction = self._make_cppfunction(meth_name, meth_idx)
-        overload = W_CPPOverload(self.space, self, [cppfunction])
+        cppfunctions = []
+        for meth_idx in indices:
+            f = self._make_cppfunction(meth_name, meth_idx)
+            cppfunctions.append(f)
+        overload = W_CPPOverload(self.space, self, cppfunctions)
         return overload
 
     def find_datamember(self, dm_name):
 
 
 class W_CPPClass(W_CPPScope):
-    _immutable_ = True
+    _attrs_ = ['space', 'default_constructor', 'name', 'handle', 'methods', 'datamembers']
+    _immutable_fields_ = ['kind', 'default_constructor', 'methods[*]', 'datamembers[*]']
+
     kind = "class"
 
     def __init__(self, space, name, opaque_handle):
 
 
 class W_ComplexCPPClass(W_CPPClass):
-    _immutable_ = True
 
     def get_cppthis(self, cppinstance, calling_scope):
         assert self == cppinstance.cppclass
 
 
 class W_CPPTemplateType(Wrappable):
-    _immutable_ = True
+    _attrs_ = ['space', 'name', 'handle']
+    _immutable_fields = ['name', 'handle']
 
     def __init__(self, space, name, opaque_handle):
         self.space = space
 
 
 class W_CPPInstance(Wrappable):
+    _attrs_ = ['space', 'cppclass', '_rawobject', 'isref', 'python_owns']
     _immutable_fields_ = ["cppclass", "isref"]
 
     def __init__(self, space, cppclass, rawobject, isref, python_owns):
             ptrptr = rffi.cast(rffi.VOIDPP, self._rawobject)
             return rffi.cast(capi.C_OBJECT, ptrptr[0])
 
+    def _get_as_builtin(self):
+        try:
+            return self.space.call_method(self.space.wrap(self), "_cppyy_as_builtin")
+        except OperationError, e:
+            if not e.match(self.space, self.space.w_AttributeError):
+                raise
+        return None
+
     def instance__eq__(self, w_other):
-        other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False)
         # get here if no class-specific overloaded operator is available, try to
         # find a global overload in gbl, in __gnu_cxx (for iterators), or in the
-        # scopes of the argument classes (TODO: implement that last)
-        for name in ["", "__gnu_cxx"]:
-            nss = scope_byname(self.space, name)
-            meth_idx = capi.c_get_global_operator(nss, self.cppclass, other.cppclass, "==")
-            if meth_idx != -1:
-                f = nss._make_cppfunction("operator==", meth_idx)
-                ol = W_CPPOverload(self.space, nss, [f])
-                # TODO: cache this operator
-                return ol.call(self, [self, w_other])
-        
-        # fallback: direct pointer comparison (the class comparison is needed since the
-        # first data member in a struct and the struct have the same address)
+        # scopes of the argument classes (TODO: implement that last option)
+        try:
+            # TODO: expecting w_other to be an W_CPPInstance is too limiting
+            other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False)
+            for name in ["", "__gnu_cxx"]:
+                nss = scope_byname(self.space, name)
+                meth_idx = capi.c_get_global_operator(nss, self.cppclass, other.cppclass, "==")
+                if meth_idx != -1:
+                    f = nss._make_cppfunction("operator==", meth_idx)
+                    ol = W_CPPOverload(self.space, nss, [f])
+                    # TODO: cache this operator (not done yet, as the above does not
+                    # select all overloads)
+                    return ol.call(self, [self, w_other])
+        except OperationError, e:
+            if not e.match(self.space, self.space.w_TypeError):
+                raise
+
+        # fallback 1: convert the object to a builin equivalent
+        w_as_builtin = self._get_as_builtin()
+        if w_as_builtin is not None:
+            return self.space.eq(w_as_builtin, w_other)
+
+        # fallback 2: direct pointer comparison (the class comparison is needed since
+        # the first data member in a struct and the struct have the same address)
+        other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False)  # TODO: factor out
         iseq = (self._rawobject == other._rawobject) and (self.cppclass == other.cppclass)
         return self.space.wrap(iseq)
 
             return self.space.w_False
         return self.space.w_True
 
+    def instance__len__(self):
+        w_as_builtin = self._get_as_builtin()
+        if w_as_builtin is not None:
+            return self.space.len(w_as_builtin)
+        raise OperationError(
+            self.space.w_TypeError,
+            self.space.wrap("'%s' has no length" % self.cppclass.name))
+
+    def instance__cmp__(self, w_other):
+        w_as_builtin = self._get_as_builtin()
+        if w_as_builtin is not None:
+            return self.space.cmp(w_as_builtin, w_other)
+        raise OperationError(
+            self.space.w_AttributeError,
+            self.space.wrap("'%s' has no attribute __cmp__" % self.cppclass.name))
+
+    def instance__repr__(self):
+        w_as_builtin = self._get_as_builtin()
+        if w_as_builtin is not None:
+            return self.space.repr(w_as_builtin)
+        return self.space.wrap("<%s object at 0x%x>" %
+                               (self.cppclass.name, rffi.cast(rffi.ULONG, self.get_rawobject())))
+
     def destruct(self):
         assert isinstance(self, W_CPPInstance)
         if self._rawobject and not self.isref:
     __eq__ = interp2app(W_CPPInstance.instance__eq__),
     __ne__ = interp2app(W_CPPInstance.instance__ne__),
     __nonzero__ = interp2app(W_CPPInstance.instance__nonzero__),
+    __len__ = interp2app(W_CPPInstance.instance__len__),
+    __cmp__ = interp2app(W_CPPInstance.instance__cmp__),
+    __repr__ = interp2app(W_CPPInstance.instance__repr__),
     destruct = interp2app(W_CPPInstance.destruct),
 )
 W_CPPInstance.typedef.acceptable_as_base_class = True

pypy/module/cppyy/pythonify.py

     except KeyError:
         pass
 
+    # general note: use 'in pyclass.__dict__' rather than 'hasattr' to prevent
+    # adding pythonizations multiple times in derived classes
+
     # map size -> __len__ (generally true for STL)
-    if hasattr(pyclass, 'size') and \
-            not hasattr(pyclass, '__len__') and callable(pyclass.size):
+    if 'size' in pyclass.__dict__ and not '__len__' in pyclass.__dict__ \
+           and callable(pyclass.size):
         pyclass.__len__ = pyclass.size
 
     # map push_back -> __iadd__ (generally true for STL)
-    if hasattr(pyclass, 'push_back') and not hasattr(pyclass, '__iadd__'):
+    if 'push_back' in pyclass.__dict__ and not '__iadd__' in pyclass.__dict__:
         def __iadd__(self, ll):
             [self.push_back(x) for x in ll]
             return self
     # not on vector, for which otherwise the user has to make sure that the
     # global == and != for its iterators are reflected, which is a hassle ...
     if not 'vector' in pyclass.__name__[:11] and \
-            (hasattr(pyclass, 'begin') and hasattr(pyclass, 'end')):
+            ('begin' in pyclass.__dict__ and 'end' in pyclass.__dict__):
         # TODO: check return type of begin() and end() for existence
         def __iter__(self):
             iter = self.begin()
         pyclass.__iter__ = __iter__
 
     # combine __getitem__ and __len__ to make a pythonized __getitem__
-    if hasattr(pyclass, '__getitem__') and hasattr(pyclass, '__len__'):
+    if '__getitem__' in pyclass.__dict__ and '__len__' in pyclass.__dict__:
         pyclass._getitem__unchecked = pyclass.__getitem__
-        if hasattr(pyclass, '__setitem__') and hasattr(pyclass, '__iadd__'):
+        if '__setitem__' in pyclass.__dict__ and '__iadd__' in pyclass.__dict__:
             pyclass.__getitem__ = python_style_sliceable_getitem
         else:
             pyclass.__getitem__ = python_style_getitem

pypy/module/cppyy/src/cintcwrapper.cxx

             break;
         }
         case 'f': {
-            assert(sizeof(float) <= sizeof(long));
-            long val = libp->para[i].obj.i;
-            void* pval = (void*)&val;
-            libp->para[i].obj.d = *(float*)pval;
+            float val = libp->para[i].obj.fl;
+            libp->para[i].obj.d = val;
             break;
         }
         case 'F': {
     return (cppyy_index_t)&g_globalfuncs[imeth];
 }
 
-cppyy_index_t cppyy_method_index_from_name(cppyy_scope_t handle, const char* name) {
+cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t handle, const char* name) {
+    std::vector<cppyy_index_t> result;
     TClassRef cr = type_from_handle(handle);
     if (cr.GetClass()) {
         gInterpreter->UpdateListOfMethods(cr.GetClass());
         while ((func = (TFunction*)next())) {
             if (strcmp(name, func->GetName()) == 0) {
                 if (func->Property() & G__BIT_ISPUBLIC)
-                    return (cppyy_index_t)imeth;
-                return (cppyy_index_t)-1;
+                    result.push_back((cppyy_index_t)imeth);
             }
             ++imeth;
         }
     }
-    TFunction* func = gROOT->GetGlobalFunction(name, NULL, kTRUE);
-    if (!func)
-        return (cppyy_index_t)-1;  // (void*)-1 is in kernel space, so invalid
-    int idx = g_globalfuncs.size();
-    g_globalfuncs.push_back(*func);
-    return (cppyy_index_t)func;
+
+    if (result.empty()) {
+        TCollection* funcs = gROOT->GetListOfGlobalFunctions(kTRUE);
+        TFunction* func = 0;
+        TIter ifunc(funcs);
+        while ((func = (TFunction*)ifunc.Next())) {
+            if (strcmp(func->GetName(), name) == 0) {
+                g_globalfuncs.push_back(*func);
+                result.push_back((cppyy_index_t)func); 
+            }
+        }
+    }
+
+    if (result.empty())
+        return (cppyy_index_t*)0;
+
+    cppyy_index_t* llresult = (cppyy_index_t*)malloc(sizeof(cppyy_index_t)*result.size()+1);
+    for (int i = 0; i < (int)result.size(); ++i) llresult[i] = result[i];
+    llresult[result.size()] = -1;
+    return llresult;
 }
 
 

pypy/module/cppyy/src/reflexcwrapper.cxx

     return (cppyy_index_t)imeth;
 }
 
-cppyy_index_t cppyy_method_index_from_name(cppyy_scope_t handle, const char* name) {
+cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t handle, const char* name) {
+    std::vector<cppyy_index_t> result;
     Reflex::Scope s = scope_from_handle(handle);
     // the following appears dumb, but the internal storage for Reflex is an
     // unsorted std::vector anyway, so there's no gain to be had in using the
         Reflex::Member m = s.FunctionMemberAt(imeth);
         if (m.Name() == name) {
             if (m.IsPublic())
-               return (cppyy_index_t)imeth;
-            return (cppyy_index_t)-1;
+                result.push_back((cppyy_index_t)imeth);
         }
     }
-    return (cppyy_index_t)-1;
+    if (result.empty())
+        return (cppyy_index_t*)0;
+    cppyy_index_t* llresult = (cppyy_index_t*)malloc(sizeof(cppyy_index_t)*result.size()+1);
+    for (int i = 0; i < (int)result.size(); ++i) llresult[i] = result[i];
+    llresult[result.size()] = -1;
+    return llresult;
 }
 
 char* cppyy_method_name(cppyy_scope_t handle, cppyy_index_t method_index) {

pypy/module/cppyy/test/overloads.cxx

 
 std::string more_overloads2::call(const dd_ol*, int) { return "dd_olptr"; }
 std::string more_overloads2::call(const dd_ol&, int) { return "dd_olref"; }
+
+
+double calc_mean(long n, const float* a)     { return calc_mean<float>(n, a); }
+double calc_mean(long n, const double* a)    { return calc_mean<double>(n, a); }
+double calc_mean(long n, const int* a)       { return calc_mean<int>(n, a); }
+double calc_mean(long n, const short* a)     { return calc_mean<short>(n, a); }
+double calc_mean(long n, const long* a)      { return calc_mean<long>(n, a); }

pypy/module/cppyy/test/overloads.h

 
 class a_overload {
 public:
-   a_overload();
-   int i1, i2;
+    a_overload();
+    int i1, i2;
 };
 
 namespace ns_a_overload {
-   class a_overload {
-   public:
-      a_overload();
-      int i1, i2;
-   };
+    class a_overload {
+    public:
+        a_overload();
+        int i1, i2;
+    };
 
-   class b_overload {
-   public:
-      int f(const std::vector<int>* v);
-   };
+    class b_overload {
+    public:
+        int f(const std::vector<int>* v);
+    };
 }
 
 namespace ns_b_overload {
-   class a_overload {
-   public:
-      a_overload();
-      int i1, i2;
-   };
+    class a_overload {
+    public:
+        a_overload();
+        int i1, i2;
+    };
 }
 
 class b_overload {
 public:
-   b_overload();
-   int i1, i2;
+    b_overload();
+    int i1, i2;
 };
 
 class c_overload {
 public:
-   c_overload();
-   int get_int(a_overload* a);
-   int get_int(ns_a_overload::a_overload* a);
-   int get_int(ns_b_overload::a_overload* a);
-   int get_int(short* p);
-   int get_int(b_overload* b);
-   int get_int(int* p);
+    c_overload();
+    int get_int(a_overload* a);
+    int get_int(ns_a_overload::a_overload* a);
+    int get_int(ns_b_overload::a_overload* a);
+    int get_int(short* p);
+    int get_int(b_overload* b);
+    int get_int(int* p);
 };
 
 class d_overload {
 public:
-   d_overload();
+    d_overload();
 //   int get_int(void* p) { return *(int*)p; }
-   int get_int(int* p);
-   int get_int(b_overload* b);
-   int get_int(short* p);
-   int get_int(ns_b_overload::a_overload* a);
-   int get_int(ns_a_overload::a_overload* a);
-   int get_int(a_overload* a);
+    int get_int(int* p);
+    int get_int(b_overload* b);
+    int get_int(short* p);
+    int get_int(ns_b_overload::a_overload* a);
+    int get_int(ns_a_overload::a_overload* a);
+    int get_int(a_overload* a);
 };
 
 
 
 class more_overloads {
 public:
-   more_overloads();
-   std::string call(const aa_ol&);
-   std::string call(const bb_ol&, void* n=0);
-   std::string call(const cc_ol&);
-   std::string call(const dd_ol&);
+    more_overloads();
+    std::string call(const aa_ol&);
+    std::string call(const bb_ol&, void* n=0);
+    std::string call(const cc_ol&);
+    std::string call(const dd_ol&);
 
-   std::string call_unknown(const dd_ol&);
+    std::string call_unknown(const dd_ol&);
 
-   std::string call(double);
-   std::string call(int);
-   std::string call1(int);
-   std::string call1(double);
+    std::string call(double);
+    std::string call(int);
+    std::string call1(int);
+    std::string call1(double);
 };
 
 class more_overloads2 {
 public:
-   more_overloads2();
-   std::string call(const bb_ol&);
-   std::string call(const bb_ol*);
+    more_overloads2();
+    std::string call(const bb_ol&);
+    std::string call(const bb_ol*);
 
-   std::string call(const dd_ol*, int);
-   std::string call(const dd_ol&, int);
+    std::string call(const dd_ol*, int);
+    std::string call(const dd_ol&, int);
 };
+
+template<typename T>
+double calc_mean(long n, const T* a) {
+    double sum = 0., sumw = 0.;
+    const T* end = a+n;
+    while (a != end) {
+        sum += *a++;
+        sumw += 1;
+    }
+
+    return sum/sumw;
+}
+
+double calc_mean(long n, const float* a);
+double calc_mean(long n, const double* a);
+double calc_mean(long n, const int* a);
+double calc_mean(long n, const short* a);
+double calc_mean(long n, const long* a);

pypy/module/cppyy/test/overloads.xml

   <class name="more_overloads" />
   <class name="more_overloads2" />
 
+  <function name="calc_mean" />
+
 </lcgdict>

pypy/module/cppyy/test/overloads_LinkDef.h

 #pragma link C++ class more_overloads;
 #pragma link C++ class more_overloads2;
 
+#pragma link C++ function calc_mean;
+
 #endif

pypy/module/cppyy/test/test_advancedcpp.py

         pp.set_address_ptr_ptr(ptr)
         assert cppyy.addressof(ptr) == 0x4321
 
-    def test09_opaque_pointer_assing(self):
+    def test09_opaque_pointer_passing(self):
         """Test passing around of opaque pointers"""
 
         import cppyy

pypy/module/cppyy/test/test_cint.py

 class AppTestCINTPythonizations:
     spaceconfig = dict(usemodules=['cppyy'])
 
+    def test01_strings(self):
+        """Test TString/TObjString compatibility"""
+
+        import cppyy
+
+        pyteststr = "aap noot mies"
+        def test_string(s1, s2):
+            assert len(s1) == len(s2)
+            assert s1 == s1
+            assert s1 == s2
+            assert s1 == str(s1)
+            assert s1 == pyteststr
+            assert s1 != "aap"
+            assert s1 != ""
+            assert s1 < "noot"
+            assert repr(s1) == repr(s2)
+
+        s1 = cppyy.gbl.TString(pyteststr)
+        test_string(s1, pyteststr)
+
+        s3 = cppyy.gbl.TObjString(pyteststr)
+        test_string(s3, pyteststr)
+
     def test03_TVector(self):
         """Test TVector2/3/T behavior"""
 

pypy/module/cppyy/test/test_crossing.py

 
 
 class AppTestCrossing(AppTestCpythonExtensionBase):
-    spaceconfig = dict(usemodules=['cpyext', 'cppyy', 'thread', '_rawffi', '_ffi', 'array'])
+    spaceconfig = dict(usemodules=['cpyext', 'cppyy', 'thread', '_rawffi', '_ffi',
+                                   'array', 'itertools', 'rctime', 'binascii'])
 
     def setup_class(cls):
         # following from AppTestCpythonExtensionBase, with cppyy added
 
         # cppyy specific additions (not that the test_dct is loaded late
         # to allow the generated extension module be loaded first)
-        cls.w_test_dct  = cls.space.wrap(test_dct)
-        cls.w_datatypes = cls.space.appexec([], """():
-            import cppyy, cpyext""")
+        cls.w_test_dct    = cls.space.wrap(test_dct)
+        cls.w_pre_imports = cls.space.appexec([], """():
+            import cppyy, ctypes""")    # prevents leak-checking complaints on ctypes
+        from pypy.module.imp.importing import get_so_extension
+        cls.w_soext = cls.space.wrap(get_so_extension(cls.space))
 
-    def setup_method(self, func):
-        AppTestCpythonExtensionBase.setup_method(self, func)
+    def test00_base_class(self):
+        """Test from cpyext; only here to see whether the imported class works"""
 
-        if hasattr(self, 'cmodule'):
-            return
+        import sys
+        init = """
+        if (Py_IsInitialized())
+            Py_InitModule("foo", NULL);
+        """
+        self.import_module(name='foo', init=init)
+        assert 'foo' in sys.modules
+
+    def test01_build_bar_extension(self):
+        """Test that builds the needed extension; runs as test to keep it loaded"""
 
         import os, ctypes
 
         if (Py_IsInitialized())
             Py_InitModule("bar", methods);
         """
+        # note: only the symbols are needed for C, none for python
         body = """
         long bar_unwrap(PyObject* arg)
         {
         };
         """
 
-        modname = self.import_module(name='bar', init=init, body=body, load_it=False)
-        from pypy.module.imp.importing import get_so_extension
-        soext = get_so_extension(self.space)
-        fullmodname = os.path.join(modname, 'bar' + soext)
+        dirname = self.import_module(name='bar', init=init, body=body, load_it=False)
+        fullmodname = os.path.join(dirname, 'bar' + self.soext)
         self.cmodule = ctypes.CDLL(fullmodname, ctypes.RTLD_GLOBAL)
 
-    def test00_base_class(self):
-        """Test from cpyext; only here to see whether the imported class works"""
-
-        import sys
-        init = """
-        if (Py_IsInitialized())
-            Py_InitModule("foo", NULL);
-        """
-        self.import_module(name='foo', init=init)
-        assert 'foo' in sys.modules
-
-    def test01_crossing_dict(self):
+    def test02_crossing_dict(self):
         """Test availability of all needed classes in the dict"""
 
         import cppyy
 
         assert crossing.A == crossing.A
 
-    def test02_send_pyobject(self):
+    def test03_send_pyobject(self):
         """Test sending a true pyobject to C++"""
 
         import cppyy
         a = crossing.A()
         assert a.unwrap(13) == 13
 
-    def test03_send_and_receive_pyobject(self):
+    def test04_send_and_receive_pyobject(self):
         """Test receiving a true pyobject from C++"""
 
         import cppyy

pypy/module/cppyy/test/test_fragile.py

 
     def setup_class(cls):
         cls.w_test_dct  = cls.space.wrap(test_dct)
-        cls.w_capi = cls.space.wrap(capi)
+        cls.w_identity = cls.space.wrap(capi.identify())
         cls.w_fragile = cls.space.appexec([], """():
             import cppyy
             return cppyy.load_reflection_info(%r)""" % (test_dct, ))
         import cppyy
         raises(RuntimeError, cppyy.load_reflection_info, "does_not_exist.so")
 
+        try:
+            cppyy.load_reflection_info("does_not_exist.so")
+        except RuntimeError, e:
+            assert "does_not_exist.so" in str(e)
+
     def test02_missing_classes(self):
         """Test (non-)access to missing classes"""
 
 
         import cppyy
 
-        if self.capi.identify() == 'CINT':   # CINT only support classes on global space
+        if self.identity == 'CINT':          # CINT only support classes on global space
             members = dir(cppyy.gbl)
             assert 'TROOT' in members
             assert 'TSystem' in members

pypy/module/cppyy/test/test_overloads.py

         raise OSError("'make' failed (see stderr)")
 
 class AppTestOVERLOADS:
-    spaceconfig = dict(usemodules=['cppyy'])
+    spaceconfig = dict(usemodules=['cppyy', 'array'])
 
     def setup_class(cls):
+        env = os.environ
         cls.w_test_dct  = cls.space.wrap(test_dct)
         cls.w_overloads = cls.space.appexec([], """():
             import cppyy
 #        assert more_overloads().call(1.)  == "double"
         assert more_overloads().call1(1)  == "int"
         assert more_overloads().call1(1.) == "double"