Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: py3.5
Changeset: r91988:b4c040585955
Date: 2017-07-28 15:33 +0100
http://bitbucket.org/pypy/pypy/changeset/b4c040585955/

Log:    hg merge default

diff too long, truncating to 2000 out of 19088 lines

diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -27,16 +27,17 @@
 ^pypy/module/cpyext/test/.+\.manifest$
 ^pypy/module/test_lib_pypy/ctypes_tests/.+\.o$
 ^pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test\.o$
-^pypy/module/cppyy/src/.+\.o$
-^pypy/module/cppyy/bench/.+\.so$
-^pypy/module/cppyy/bench/.+\.root$
-^pypy/module/cppyy/bench/.+\.d$
-^pypy/module/cppyy/src/.+\.errors$
-^pypy/module/cppyy/test/.+_rflx\.cpp$
-^pypy/module/cppyy/test/.+\.so$
-^pypy/module/cppyy/test/.+\.rootmap$
-^pypy/module/cppyy/test/.+\.exe$
-^pypy/module/cppyy/test/.+_cint.h$
+^pypy/module/_cppyy/src/.+\.o$
+^pypy/module/_cppyy/bench/.+\.so$
+^pypy/module/_cppyy/bench/.+\.root$
+^pypy/module/_cppyy/bench/.+\.d$
+^pypy/module/_cppyy/src/.+\.errors$
+^pypy/module/_cppyy/test/.+_rflx\.cpp$
+^pypy/module/_cppyy/test/.+\.so$
+^pypy/module/_cppyy/test/.+\.rootmap$
+^pypy/module/_cppyy/test/.+\.exe$
+^pypy/module/_cppyy/test/.+_cint.h$
+^pypy/module/_cppyy/.+/*\.pcm$
 ^pypy/module/test_lib_pypy/cffi_tests/__pycache__.+$
 ^pypy/doc/.+\.html$
 ^pypy/doc/config/.+\.rst$
@@ -93,6 +94,3 @@
 ^release/
 ^rpython/_cache$
 
-pypy/module/cppyy/.+/*\.pcm
-
-
diff --git a/lib_pypy/_tkinter/tklib_build.py b/lib_pypy/_tkinter/tklib_build.py
--- a/lib_pypy/_tkinter/tklib_build.py
+++ b/lib_pypy/_tkinter/tklib_build.py
@@ -22,12 +22,27 @@
     linklibs = ['tcl', 'tk']
     libdirs = []
 else:
-    for _ver in ['', '8.6', '8.5', '']:
+    # On some Linux distributions, the tcl and tk libraries are
+    # stored in /usr/include, so we must check this case also
+    libdirs = []
+    found = False
+    for _ver in ['', '8.6', '8.5']:
         incdirs = ['/usr/include/tcl' + _ver]
         linklibs = ['tcl' + _ver, 'tk' + _ver]
-        libdirs = []
         if os.path.isdir(incdirs[0]):
+            found = True
             break
+    if not found:
+        for _ver in ['8.6', '8.5', '']:
+            incdirs = []
+            linklibs = ['tcl' + _ver, 'tk' + _ver]
+            if os.path.isfile(''.join(['/usr/lib/lib', linklibs[1], '.so'])):
+                found = True
+                break
+    if not found:
+        sys.stderr.write("*** TCL libraries not found!  Falling back...\n")
+        incdirs = []
+        linklibs = ['tcl', 'tk']
 
 config_ffi = FFI()
 config_ffi.cdef("""
diff --git a/lib_pypy/cffi/_cffi_include.h b/lib_pypy/cffi/_cffi_include.h
--- a/lib_pypy/cffi/_cffi_include.h
+++ b/lib_pypy/cffi/_cffi_include.h
@@ -95,6 +95,7 @@
 #define _cffi_from_c_ulong PyLong_FromUnsignedLong
 #define _cffi_from_c_longlong PyLong_FromLongLong
 #define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong
+#define _cffi_from_c__Bool PyBool_FromLong
 
 #define _cffi_to_c_double PyFloat_AsDouble
 #define _cffi_to_c_float PyFloat_AsDouble
diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h
--- a/lib_pypy/cffi/_embedding.h
+++ b/lib_pypy/cffi/_embedding.h
@@ -1,7 +1,12 @@
 
 /***** Support code for embedding *****/
 
-#if defined(_MSC_VER)
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if defined(_WIN32)
 #  define CFFI_DLLEXPORT  __declspec(dllexport)
 #elif defined(__GNUC__)
 #  define CFFI_DLLEXPORT  __attribute__((visibility("default")))
@@ -525,3 +530,7 @@
 #undef cffi_compare_and_swap
 #undef cffi_write_barrier
 #undef cffi_read_barrier
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py
--- a/lib_pypy/cffi/recompiler.py
+++ b/lib_pypy/cffi/recompiler.py
@@ -412,6 +412,9 @@
             prnt('    }')
         prnt('    p[0] = (const void *)0x%x;' % self._version)
         prnt('    p[1] = &_cffi_type_context;')
+        prnt('#if PY_MAJOR_VERSION >= 3')
+        prnt('    return NULL;')
+        prnt('#endif')
         prnt('}')
         # on Windows, distutils insists on putting init_cffi_xyz in
         # 'export_symbols', so instead of fighting it, just give up and
@@ -578,7 +581,7 @@
 
     def _convert_expr_from_c(self, tp, var, context):
         if isinstance(tp, model.BasePrimitiveType):
-            if tp.is_integer_type():
+            if tp.is_integer_type() and tp.name != '_Bool':
                 return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
             elif isinstance(tp, model.UnknownFloatType):
                 return '_cffi_from_c_double(%s)' % (var,)
diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py
--- a/lib_pypy/cffi/vengine_cpy.py
+++ b/lib_pypy/cffi/vengine_cpy.py
@@ -296,7 +296,7 @@
 
     def _convert_expr_from_c(self, tp, var, context):
         if isinstance(tp, model.PrimitiveType):
-            if tp.is_integer_type():
+            if tp.is_integer_type() and tp.name != '_Bool':
                 return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
             elif tp.name != 'long double':
                 return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
@@ -872,6 +872,7 @@
 #define _cffi_from_c_ulong PyLong_FromUnsignedLong
 #define _cffi_from_c_longlong PyLong_FromLongLong
 #define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong
+#define _cffi_from_c__Bool PyBool_FromLong
 
 #define _cffi_to_c_double PyFloat_AsDouble
 #define _cffi_to_c_float PyFloat_AsDouble
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -39,7 +39,7 @@
     "thread", "itertools", "pyexpat", "cpyext", "array",
     "binascii", "_multiprocessing", '_warnings', "_collections",
     "_multibytecodec", "_continuation", "_cffi_backend",
-    "_csv", "_pypyjson", "_posixsubprocess", # "cppyy", "micronumpy"
+    "_csv", "_pypyjson", "_posixsubprocess", # "_cppyy", "micronumpy"
     "_jitlog",
 ])
 
@@ -71,8 +71,8 @@
         if name in translation_modules:
             translation_modules.remove(name)
 
-    if "cppyy" in working_modules:
-        working_modules.remove("cppyy")  # not tested on win32
+    if "_cppyy" in working_modules:
+        working_modules.remove("_cppyy")  # not tested on win32
 
     # The _locale module is needed by site.py on Windows
     default_modules.add("_locale")
@@ -81,8 +81,8 @@
     working_modules.remove('fcntl')  # LOCK_NB not defined
     working_modules.remove("_minimal_curses")
     working_modules.remove("termios")
-    if "cppyy" in working_modules:
-        working_modules.remove("cppyy")  # depends on ctypes
+    if "_cppyy" in working_modules:
+        working_modules.remove("_cppyy")  # depends on ctypes
 
 #if sys.platform.startswith("linux"):
 #    _mach = os.popen('uname -m', 'r').read().strip()
@@ -94,7 +94,7 @@
     '_multiprocessing': [('objspace.usemodules.time', True),
                          ('objspace.usemodules.thread', True)],
     'cpyext': [('objspace.usemodules.array', True)],
-    'cppyy': [('objspace.usemodules.cpyext', True)],
+    '_cppyy': [('objspace.usemodules.cpyext', True)],
     'faulthandler': [('objspace.usemodules._vmprof', True)],
     }
 module_suggests = {
diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
deleted file mode 100644
--- a/pypy/doc/cppyy.rst
+++ /dev/null
@@ -1,672 +0,0 @@
-cppyy: C++ bindings for PyPy
-============================
-
-The cppyy module delivers dynamic Python-C++ bindings.
-It is designed for automation, high performance, scale, interactivity, and
-handling all of modern C++ (11, 14, etc.).
-It is based on `Cling`_ which, through `LLVM`_/`clang`_, provides C++
-reflection and interactivity.
-Reflection information is extracted from C++ header files.
-Cppyy itself is built into PyPy (an alternative exists for CPython), but
-it requires a `backend`_, installable through pip, to interface with Cling.
-
-.. _Cling: https://root.cern.ch/cling
-.. _LLVM: http://llvm.org/
-.. _clang: http://clang.llvm.org/
-.. _backend: https://pypi.python.org/pypi/PyPy-cppyy-backend
-
-
-Installation
-------------
-
-This assumes PyPy2.7 v5.7 or later; earlier versions use a Reflex-based cppyy
-module, which is no longer supported.
-Both the tooling and user-facing Python codes are very backwards compatible,
-however.
-Further dependencies are cmake (for general build), Python2.7 (for LLVM), and
-a modern C++ compiler (one that supports at least C++11).
-
-Assuming you have a recent enough version of PyPy installed, use pip to
-complete the installation of cppyy::
-
- $ MAKE_NPROCS=4 pypy-c -m pip install --verbose PyPy-cppyy-backend
-
-Set the number of parallel builds ('4' in this example, through the MAKE_NPROCS
-environment variable) to a number appropriate for your machine.
-The building process may take quite some time as it includes a customized
-version of LLVM as part of Cling, which is why --verbose is recommended so that
-you can see the build progress.
-
-The default installation will be under
-$PYTHONHOME/site-packages/cppyy_backend/lib,
-which needs to be added to your dynamic loader path (LD_LIBRARY_PATH).
-If you need the dictionary and class map generation tools (used in the examples
-below), you need to add $PYTHONHOME/site-packages/cppyy_backend/bin to your
-executable path (PATH).
-
-
-Basic bindings example
-----------------------
-
-These examples assume that cppyy_backend is pointed to by the environment
-variable CPPYYHOME, and that CPPYYHOME/lib is added to LD_LIBRARY_PATH and
-CPPYYHOME/bin to PATH.
-
-Let's first test with a trivial example whether all packages are properly
-installed and functional.
-Create a C++ header file with some class in it (all functions are made inline
-for convenience; if you have out-of-line code, link with it as appropriate)::
-
-    $ cat MyClass.h
-    class MyClass {
-    public:
-        MyClass(int i = -99) : m_myint(i) {}
-
-        int GetMyInt() { return m_myint; }
-        void SetMyInt(int i) { m_myint = i; }
-
-    public:
-        int m_myint;
-    };
-
-Then, generate the bindings using ``genreflex`` (installed under
-cppyy_backend/bin in site_packages), and compile the code::
-
-    $ genreflex MyClass.h
-    $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared -I$CPPYYHOME/include 
MyClass_rflx.cpp -o libMyClassDict.so -L$CPPYYHOME/lib -lCling
-
-Next, make sure that the library can be found through the dynamic lookup path
-(the ``LD_LIBRARY_PATH`` environment variable on Linux, ``PATH`` on Windows),
-for example by adding ".".
-Now you're ready to use the bindings.
-Since the bindings are designed to look pythonistic, it should be
-straightforward::
-
-    $ pypy-c
-    >>>> import cppyy
-    >>>> cppyy.load_reflection_info("libMyClassDict.so")
-    <CPPLibrary object at 0xb6fd7c4c>
-    >>>> myinst = cppyy.gbl.MyClass(42)
-    >>>> print myinst.GetMyInt()
-    42
-    >>>> myinst.SetMyInt(33)
-    >>>> print myinst.m_myint
-    33
-    >>>> myinst.m_myint = 77
-    >>>> print myinst.GetMyInt()
-    77
-    >>>> help(cppyy.gbl.MyClass)   # shows that normal python introspection 
works
-
-That's all there is to it!
-
-
-Automatic class loader
-----------------------
-
-There is one big problem in the code above, that prevents its use in a (large
-scale) production setting: the explicit loading of the reflection library.
-Clearly, if explicit load statements such as these show up in code downstream
-from the ``MyClass`` package, then that prevents the ``MyClass`` author from
-repackaging or even simply renaming the dictionary library.
-
-The solution is to make use of an automatic class loader, so that downstream
-code never has to call ``load_reflection_info()`` directly.
-The class loader makes use of so-called rootmap files, which ``genreflex``
-can produce.
-These files contain the list of available C++ classes and specify the library
-that needs to be loaded for their use (as an aside, this listing allows for a
-cross-check to see whether reflection info is generated for all classes that
-you expect).
-By convention, the rootmap files should be located next to the reflection info
-libraries, so that they can be found through the normal shared library search
-path.
-They can be concatenated together, or consist of a single rootmap file per
-library.
-For example::
-
-    $ genreflex MyClass.h --rootmap=libMyClassDict.rootmap 
--rootmap-lib=libMyClassDict.so
-    $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared -I$CPPYYHOME/include 
MyClass_rflx.cpp -o libMyClassDict.so -L$CPPYYHOME/lib -lCling
-
-where the first option (``--rootmap``) specifies the output file name, and the
-second option (``--rootmap-lib``) the name of the reflection library where
-``MyClass`` will live.
-It is necessary to provide that name explicitly, since it is only in the
-separate linking step where this name is fixed.
-If the second option is not given, the library is assumed to be libMyClass.so,
-a name that is derived from the name of the header file.
-
-With the rootmap file in place, the above example can be rerun without explicit
-loading of the reflection info library::
-
-    $ pypy-c
-    >>>> import cppyy
-    >>>> myinst = cppyy.gbl.MyClass(42)
-    >>>> print myinst.GetMyInt()
-    42
-    >>>> # etc. ...
-
-As a caveat, note that the class loader is currently limited to classes only.
-
-
-Advanced example
-----------------
-
-The following snippet of C++ is very contrived, to allow showing that such
-pathological code can be handled and to show how certain features play out in
-practice::
-
-    $ cat MyAdvanced.h
-    #include <string>
-
-    class Base1 {
-    public:
-        Base1(int i) : m_i(i) {}
-        virtual ~Base1() {}
-        int m_i;
-    };
-
-    class Base2 {
-    public:
-        Base2(double d) : m_d(d) {}
-        virtual ~Base2() {}
-        double m_d;
-    };
-
-    class C;
-
-    class Derived : public virtual Base1, public virtual Base2 {
-    public:
-        Derived(const std::string& name, int i, double d) : Base1(i), 
Base2(d), m_name(name) {}
-        virtual C* gimeC() { return (C*)0; }
-        std::string m_name;
-    };
-
-    Base2* BaseFactory(const std::string& name, int i, double d) {
-        return new Derived(name, i, d);
-    }
-
-This code is still only in a header file, with all functions inline, for
-convenience of the example.
-If the implementations live in a separate source file or shared library, the
-only change needed is to link those in when building the reflection library.
-
-If you were to run ``genreflex`` like above in the basic example, you will
-find that not all classes of interest will be reflected, nor will be the
-global factory function.
-In particular, ``std::string`` will be missing, since it is not defined in
-this header file, but in a header file that is included.
-In practical terms, general classes such as ``std::string`` should live in a
-core reflection set, but for the moment assume we want to have it in the
-reflection library that we are building for this example.
-
-The ``genreflex`` script can be steered using a so-called `selection file`_
-(see "Generating Reflex Dictionaries")
-which is a simple XML file specifying, either explicitly or by using a
-pattern, which classes, variables, namespaces, etc. to select from the given
-header file.
-With the aid of a selection file, a large project can be easily managed:
-simply ``#include`` all relevant headers into a single header file that is
-handed to ``genreflex``.
-In fact, if you hand multiple header files to ``genreflex``, then a selection
-file is almost obligatory: without it, only classes from the last header will
-be selected.
-Then, apply a selection file to pick up all the relevant classes.
-For our purposes, the following rather straightforward selection will do
-(the name ``lcgdict`` for the root is historical, but required)::
-
-    $ cat MyAdvanced.xml
-    <lcgdict>
-        <class pattern="Base?" />
-        <class name="Derived" />
-        <class name="std::string" />
-        <function name="BaseFactory" />
-    </lcgdict>
-
-.. _selection file: https://root.cern.ch/how/how-use-reflex
-
-Now the reflection info can be generated and compiled::
-
-    $ genreflex MyAdvanced.h --selection=MyAdvanced.xml
-    $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared -I$CPPYYHOME/include 
MyAdvanced_rflx.cpp -o libAdvExDict.so -L$CPPYYHOME/lib -lCling
-
-and subsequently be used from PyPy::
-
-    >>>> import cppyy
-    >>>> cppyy.load_reflection_info("libAdvExDict.so")
-    <CPPLibrary object at 0x00007fdb48fc8120>
-    >>>> d = cppyy.gbl.BaseFactory("name", 42, 3.14)
-    >>>> type(d)
-    <class '__main__.Derived'>
-    >>>> isinstance(d, cppyy.gbl.Base1)
-    True
-    >>>> isinstance(d, cppyy.gbl.Base2)
-    True
-    >>>> d.m_i, d.m_d
-    (42, 3.14)
-    >>>> d.m_name == "name"
-    True
-    >>>>
-
-Again, that's all there is to it!
-
-A couple of things to note, though.
-If you look back at the C++ definition of the ``BaseFactory`` function,
-you will see that it declares the return type to be a ``Base2``, yet the
-bindings return an object of the actual type ``Derived``?
-This choice is made for a couple of reasons.
-First, it makes method dispatching easier: if bound objects are always their
-most derived type, then it is easy to calculate any offsets, if necessary.
-Second, it makes memory management easier: the combination of the type and
-the memory address uniquely identifies an object.
-That way, it can be recycled and object identity can be maintained if it is
-entered as a function argument into C++ and comes back to PyPy as a return
-value.
-Last, but not least, casting is decidedly unpythonistic.
-By always providing the most derived type known, casting becomes unnecessary.
-For example, the data member of ``Base2`` is simply directly available.
-Note also that the unreflected ``gimeC`` method of ``Derived`` does not
-preclude its use.
-It is only the ``gimeC`` method that is unusable as long as class ``C`` is
-unknown to the system.
-
-
-Features
---------
-
-The following is not meant to be an exhaustive list, since cppyy is still
-under active development.
-Furthermore, the intention is that every feature is as natural as possible on
-the python side, so if you find something missing in the list below, simply
-try it out.
-It is not always possible to provide exact mapping between python and C++
-(active memory management is one such case), but by and large, if the use of a
-feature does not strike you as obvious, it is more likely to simply be a bug.
-That is a strong statement to make, but also a worthy goal.
-For the C++ side of the examples, refer to this :doc:`example code 
<cppyy_example>`, which was
-bound using::
-
-    $ genreflex example.h --deep --rootmap=libexampleDict.rootmap 
--rootmap-lib=libexampleDict.so
-    $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared -I$CPPYYHOME/include 
example_rflx.cpp -o libexampleDict.so -L$CPPYYHOME/lib -lCling
-
-* **abstract classes**: Are represented as python classes, since they are
-  needed to complete the inheritance hierarchies, but will raise an exception
-  if an attempt is made to instantiate from them.
-  Example::
-
-    >>>> from cppyy.gbl import AbstractClass, ConcreteClass
-    >>>> a = AbstractClass()
-    Traceback (most recent call last):
-      File "<console>", line 1, in <module>
-    TypeError: cannot instantiate abstract class 'AbstractClass'
-    >>>> issubclass(ConcreteClass, AbstractClass)
-    True
-    >>>> c = ConcreteClass()
-    >>>> isinstance(c, AbstractClass)
-    True
-    >>>>
-
-* **arrays**: Supported for builtin data types only, as used from module
-  ``array``.
-  Out-of-bounds checking is limited to those cases where the size is known at
-  compile time (and hence part of the reflection info).
-  Example::
-
-    >>>> from cppyy.gbl import ConcreteClass
-    >>>> from array import array
-    >>>> c = ConcreteClass()
-    >>>> c.array_method(array('d', [1., 2., 3., 4.]), 4)
-    1 2 3 4
-    >>>>
-
-* **builtin data types**: Map onto the expected equivalent python types, with
-  the caveat that there may be size differences, and thus it is possible that
-  exceptions are raised if an overflow is detected.
-
-* **casting**: Is supposed to be unnecessary.
-  Object pointer returns from functions provide the most derived class known
-  in the hierarchy of the object being returned.
-  This is important to preserve object identity as well as to make casting,
-  a pure C++ feature after all, superfluous.
-  Example::
-
-    >>>> from cppyy.gbl import AbstractClass, ConcreteClass
-    >>>> c = ConcreteClass()
-    >>>> ConcreteClass.show_autocast.__doc__
-    'AbstractClass* ConcreteClass::show_autocast()'
-    >>>> d = c.show_autocast()
-    >>>> type(d)
-    <class '__main__.ConcreteClass'>
-    >>>>
-
-  However, if need be, you can perform C++-style reinterpret_casts (i.e.
-  without taking offsets into account), by taking and rebinding the address
-  of an object::
-
-    >>>> from cppyy import addressof, bind_object
-    >>>> e = bind_object(addressof(d), AbstractClass)
-    >>>> type(e)
-    <class '__main__.AbstractClass'>
-    >>>>
-
-* **classes and structs**: Get mapped onto python classes, where they can be
-  instantiated as expected.
-  If classes are inner classes or live in a namespace, their naming and
-  location will reflect that.
-  Example::
-
-    >>>> from cppyy.gbl import ConcreteClass, Namespace
-    >>>> ConcreteClass == Namespace.ConcreteClass
-    False
-    >>>> n = Namespace.ConcreteClass.NestedClass()
-    >>>> type(n)
-    <class '__main__.Namespace::ConcreteClass::NestedClass'>
-    >>>>
-
-* **data members**: Public data members are represented as python properties
-  and provide read and write access on instances as expected.
-  Private and protected data members are not accessible.
-  Example::
-
-    >>>> from cppyy.gbl import ConcreteClass
-    >>>> c = ConcreteClass()
-    >>>> c.m_int
-    42
-    >>>>
-
-* **default arguments**: C++ default arguments work as expected, but python
-  keywords are not supported.
-  It is technically possible to support keywords, but for the C++ interface,
-  the formal argument names have no meaning and are not considered part of the
-  API, hence it is not a good idea to use keywords.
-  Example::
-
-    >>>> from cppyy.gbl import ConcreteClass
-    >>>> c = ConcreteClass()       # uses default argument
-    >>>> c.m_int
-    42
-    >>>> c = ConcreteClass(13)
-    >>>> c.m_int
-    13
-    >>>>
-
-* **doc strings**: The doc string of a method or function contains the C++
-  arguments and return types of all overloads of that name, as applicable.
-  Example::
-
-    >>>> from cppyy.gbl import ConcreteClass
-    >>>> print ConcreteClass.array_method.__doc__
-    void ConcreteClass::array_method(int*, int)
-    void ConcreteClass::array_method(double*, int)
-    >>>>
-
-* **enums**: Are translated as ints with no further checking.
-
-* **functions**: Work as expected and live in their appropriate namespace
-  (which can be the global one, ``cppyy.gbl``).
-
-* **inheritance**: All combinations of inheritance on the C++ (single,
-  multiple, virtual) are supported in the binding.
-  However, new python classes can only use single inheritance from a bound C++
-  class.
-  Multiple inheritance would introduce two "this" pointers in the binding.
-  This is a current, not a fundamental, limitation.
-  The C++ side will not see any overridden methods on the python side, as
-  cross-inheritance is planned but not yet supported.
-  Example::
-
-    >>>> from cppyy.gbl import ConcreteClass
-    >>>> help(ConcreteClass)
-    Help on class ConcreteClass in module __main__:
-
-    class ConcreteClass(AbstractClass)
-     |  Method resolution order:
-     |      ConcreteClass
-     |      AbstractClass
-     |      cppyy.CPPObject
-     |      __builtin__.CPPInstance
-     |      __builtin__.object
-     |
-     |  Methods defined here:
-     |
-     |  ConcreteClass(self, *args)
-     |      ConcreteClass::ConcreteClass(const ConcreteClass&)
-     |      ConcreteClass::ConcreteClass(int)
-     |      ConcreteClass::ConcreteClass()
-     |
-     etc. ....
-
-* **memory**: C++ instances created by calling their constructor from python
-  are owned by python.
-  You can check/change the ownership with the _python_owns flag that every
-  bound instance carries.
-  Example::
-
-    >>>> from cppyy.gbl import ConcreteClass
-    >>>> c = ConcreteClass()
-    >>>> c._python_owns            # True: object created in Python
-    True
-    >>>>
-
-* **methods**: Are represented as python methods and work as expected.
-  They are first class objects and can be bound to an instance.
-  Virtual C++ methods work as expected.
-  To select a specific virtual method, do like with normal python classes
-  that override methods: select it from the class that you need, rather than
-  calling the method on the instance.
-  To select a specific overload, use the __dispatch__ special function, which
-  takes the name of the desired method and its signature (which can be
-  obtained from the doc string) as arguments.
-
-* **namespaces**: Are represented as python classes.
-  Namespaces are more open-ended than classes, so sometimes initial access may
-  result in updates as data and functions are looked up and constructed
-  lazily.
-  Thus the result of ``dir()`` on a namespace shows the classes available,
-  even if they may not have been created yet.
-  It does not show classes that could potentially be loaded by the class
-  loader.
-  Once created, namespaces are registered as modules, to allow importing from
-  them.
-  Namespace currently do not work with the class loader.
-  Fixing these bootstrap problems is on the TODO list.
-  The global namespace is ``cppyy.gbl``.
-
-* **NULL**: Is represented as ``cppyy.gbl.nullptr``.
-  In C++11, the keyword ``nullptr`` is used to represent ``NULL``.
-  For clarity of intent, it is recommended to use this instead of ``None``
-  (or the integer ``0``, which can serve in some cases), as ``None`` is better
-  understood as ``void`` in C++.
-
-* **operator conversions**: If defined in the C++ class and a python
-  equivalent exists (i.e. all builtin integer and floating point types, as well
-  as ``bool``), it will map onto that python conversion.
-  Note that ``char*`` is mapped onto ``__str__``.
-  Example::
-
-    >>>> from cppyy.gbl import ConcreteClass
-    >>>> print ConcreteClass()
-    Hello operator const char*!
-    >>>>
-
-* **operator overloads**: If defined in the C++ class and if a python
-  equivalent is available (not always the case, think e.g. of ``operator||``),
-  then they work as expected.
-  Special care needs to be taken for global operator overloads in C++: first,
-  make sure that they are actually reflected, especially for the global
-  overloads for ``operator==`` and ``operator!=`` of STL vector iterators in
-  the case of gcc (note that they are not needed to iterate over a vector).
-  Second, make sure that reflection info is loaded in the proper order.
-  I.e. that these global overloads are available before use.
-
-* **pointers**: For builtin data types, see arrays.
-  For objects, a pointer to an object and an object looks the same, unless
-  the pointer is a data member.
-  In that case, assigning to the data member will cause a copy of the pointer
-  and care should be taken about the object's life time.
-  If a pointer is a global variable, the C++ side can replace the underlying
-  object and the python side will immediately reflect that.
-
-* **PyObject***: Arguments and return types of ``PyObject*`` can be used, and
-  passed on to CPython API calls.
-  Since these CPython-like objects need to be created and tracked (this all
-  happens through ``cpyext``) this interface is not particularly fast.
-
-* **static data members**: Are represented as python property objects on the
-  class and the meta-class.
-  Both read and write access is as expected.
-
-* **static methods**: Are represented as python's ``staticmethod`` objects
-  and can be called both from the class as well as from instances.
-
-* **strings**: The std::string class is considered a builtin C++ type and
-  mixes quite well with python's str.
-  Python's str can be passed where a ``const char*`` is expected, and an str
-  will be returned if the return type is ``const char*``.
-
-* **templated classes**: Are represented in a meta-class style in python.
-  This may look a little bit confusing, but conceptually is rather natural.
-  For example, given the class ``std::vector<int>``, the meta-class part would
-  be ``std.vector``.
-  Then, to get the instantiation on ``int``, do ``std.vector(int)`` and to
-  create an instance of that class, do ``std.vector(int)()``::
-
-    >>>> import cppyy
-    >>>> cppyy.load_reflection_info('libexampleDict.so')
-    >>>> cppyy.gbl.std.vector                # template metatype
-    <cppyy.CppyyTemplateType object at 0x00007fcdd330f1a0>
-    >>>> cppyy.gbl.std.vector(int)           # instantiates template -> class
-    <class '__main__.std::vector<int>'>
-    >>>> cppyy.gbl.std.vector(int)()         # instantiates class -> object
-    <__main__.std::vector<int> object at 0x00007fe480ba4bc0>
-    >>>>
-
-  Note that templates can be build up by handing actual types to the class
-  instantiation (as done in this vector example), or by passing in the list of
-  template arguments as a string.
-  The former is a lot easier to work with if you have template instantiations
-  using classes that themselves are templates in  the arguments (think e.g a
-  vector of vectors).
-  All template classes must already exist in the loaded reflection info, they
-  do not work (yet) with the class loader.
-
-  For compatibility with other bindings generators, use of square brackets
-  instead of parenthesis to instantiate templates is supported as well.
-
-* **templated functions**: Automatically participate in overloading and are
-  used in the same way as other global functions.
-
-* **templated methods**: For now, require an explicit selection of the
-  template parameters.
-  This will be changed to allow them to participate in overloads as expected.
-
-* **typedefs**: Are simple python references to the actual classes to which
-  they refer.
-
-* **unary operators**: Are supported if a python equivalent exists, and if the
-  operator is defined in the C++ class.
-
-You can always find more detailed examples and see the full of supported
-features by looking at the tests in pypy/module/cppyy/test.
-
-If a feature or reflection info is missing, this is supposed to be handled
-gracefully.
-In fact, there are unit tests explicitly for this purpose (even as their use
-becomes less interesting over time, as the number of missing features
-decreases).
-Only when a missing feature is used, should there be an exception.
-For example, if no reflection info is available for a return type, then a
-class that has a method with that return type can still be used.
-Only that one specific method can not be used.
-
-
-Templates
----------
-
-Templates can be automatically instantiated, assuming the appropriate header
-files have been loaded or are accessible to the class loader.
-This is the case for example for all of STL.
-For example::
-
-    $ cat MyTemplate.h
-    #include <vector>
-
-    class MyClass {
-    public:
-        MyClass(int i = -99) : m_i(i) {}
-        MyClass(const MyClass& s) : m_i(s.m_i) {}
-        MyClass& operator=(const MyClass& s) { m_i = s.m_i; return *this; }
-        ~MyClass() {}
-        int m_i;
-    };
-
-Run the normal ``genreflex`` and compilation steps::
-
-    $ genreflex MyTemplate.h --selection=MyTemplate.xml
-    $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared -I$CPPYYHOME/include 
MyTemplate_rflx.cpp -o libTemplateDict.so -L$CPPYYHOME/lib -lCling
-
-Subsequent use should be as expected.
-Note the meta-class style of "instantiating" the template::
-
-    >>>> import cppyy
-    >>>> cppyy.load_reflection_info("libTemplateDict.so")
-    >>>> std = cppyy.gbl.std
-    >>>> MyClass = cppyy.gbl.MyClass
-    >>>> v = std.vector(MyClass)()
-    >>>> v += [MyClass(1), MyClass(2), MyClass(3)]
-    >>>> for m in v:
-    ....     print m.m_i,
-    ....
-    1 2 3
-    >>>>
-
-The arguments to the template instantiation can either be a string with the
-full list of arguments, or the explicit classes.
-The latter makes for easier code writing if the classes passed to the
-instantiation are themselves templates.
-
-
-The fast lane
--------------
-
-By default, cppyy will use direct function pointers through `CFFI`_ whenever
-possible. If this causes problems for you, you can disable it by setting the
-CPPYY_DISABLE_FASTPATH environment variable.
-
-.. _CFFI: https://cffi.readthedocs.io/en/latest/
-
-
-CPython
--------
-
-Most of the ideas in cppyy come originally from the `PyROOT`_ project, which
-contains a CPython-based cppyy.py module (with similar dependencies as the
-one that comes with PyPy).
-A standalone pip-installable version is planned, but for now you can install
-ROOT through your favorite distribution installer (available in the science
-section).
-
-.. _PyROOT: https://root.cern.ch/pyroot
-
-There are a couple of minor differences between the two versions of cppyy
-(the CPython version has a few more features).
-Work is on-going to integrate the nightly tests of both to make sure their
-feature sets are equalized.
-
-
-Python3
--------
-
-The CPython version of cppyy supports Python3, assuming your packager has
-build the backend for it.
-The cppyy module has not been tested with the `Py3k`_ version of PyPy.
-Note that the generated reflection information (from ``genreflex``) is fully
-independent of Python, and does not need to be rebuild when switching versions
-or interpreters.
-
-.. _Py3k: https://bitbucket.org/pypy/pypy/src/py3k
-
-
-.. toctree::
-   :hidden:
-
-   cppyy_example
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -337,6 +337,8 @@
 
  - ``frozenset`` (empty frozenset only)
 
+ - unbound method objects (for Python 2 only)
+
 This change requires some changes to ``id`` as well. ``id`` fulfills the
 following condition: ``x is y <=> id(x) == id(y)``. Therefore ``id`` of the
 above types will return a value that is computed from the argument, and can
diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst
--- a/pypy/doc/extending.rst
+++ b/pypy/doc/extending.rst
@@ -61,29 +61,23 @@
 .. _libffi: http://sourceware.org/libffi/
 
 
-Cling and cppyy
----------------
+cppyy
+-----
 
-The builtin :doc:`cppyy <cppyy>` module uses reflection information, provided 
by
-`Cling`_ (which needs to be `installed separately`_), of C/C++ code to
-automatically generate bindings at runtime.
-In Python, classes and functions are always runtime structures, so when they
-are generated matters not for performance.
-However, if the backend itself is capable of dynamic behavior, it is a much
-better functional match, allowing tighter integration and more natural
-language mappings.
+For C++, `cppyy`_ is an automated bindings generator available for both
+PyPy and CPython.
+``cppyy`` relies on declarations from C++ header files to dynamically
+construct Python equivalent classes, functions, variables, etc.
+It is designed for use by large scale programs and supports modern C++.
+With PyPy, it leverages the built-in ``_cppyy`` module, allowing the JIT to
+remove most of the cross-language overhead.
 
-The :doc:`cppyy <cppyy>` module is written in RPython, thus PyPy's JIT is able 
to remove
-most cross-language call overhead.
+To install, run ``pip install cppyy``.
+Further details are available in the `full documentation`_.
 
-:doc:Full details are `available here <cppyy>`.
+.. _cppyy: http://cppyy.readthedocs.org/
+.. _`full documentation`: http://cppyy.readthedocs.org/
 
-.. _installed separately: https://pypi.python.org/pypi/PyPy-cppyy-backend
-.. _Cling: https://root.cern.ch/cling
-
-.. toctree::
-
-   cppyy
 
 RPython Mixed Modules
 ---------------------
diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst
--- a/pypy/doc/how-to-release.rst
+++ b/pypy/doc/how-to-release.rst
@@ -40,6 +40,9 @@
   sure things are ported back to the trunk and to the branch as
   necessary.
 
+* Maybe bump the SOABI number in module/imp/importing. This has many
+  implications, so make sure the PyPy community agrees to the change.
+
 * Update and write documentation
 
   * update pypy/doc/contributor.rst (and possibly LICENSE)
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -25,3 +25,8 @@
 .. branch: cpyext-hash_notimpl
 
 If ``tp_hash`` is ``PyObject_HashNotImplemented``, set 
``obj.__dict__['__hash__']`` to None
+
+.. branch: cppyy-packaging
+
+Renaming of ``cppyy`` to ``_cppyy``.
+The former is now an external package installable with ``pip install cppyy``.
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py 
b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -3838,6 +3838,7 @@
         assert result == samples
         for i in range(len(samples)):
             assert result[i] == p[i] and type(result[i]) is type(p[i])
+            assert (type(result[i]) is bool) == (type(samples[i]) is bool)
     #
     BInt = new_primitive_type("int")
     py.test.raises(TypeError, unpack, p)
diff --git a/pypy/module/cppyy/__init__.py b/pypy/module/_cppyy/__init__.py
rename from pypy/module/cppyy/__init__.py
rename to pypy/module/_cppyy/__init__.py
--- a/pypy/module/cppyy/__init__.py
+++ b/pypy/module/_cppyy/__init__.py
@@ -33,11 +33,11 @@
 
         # pythonization functions may be written in RPython, but the interp2app
         # code generation is not, so give it a chance to run now
-        from pypy.module.cppyy import capi
+        from pypy.module._cppyy import capi
         capi.register_pythonizations(space)
 
     def startup(self, space):
-        from pypy.module.cppyy import capi
+        from pypy.module._cppyy import capi
         capi.verify_backend(space)      # may raise ImportError
 
         space.call_method(self, '_init_pythonify')
diff --git a/pypy/module/cppyy/backend/create_cppyy_package.py 
b/pypy/module/_cppyy/backend/create_cppyy_package.py
rename from pypy/module/cppyy/backend/create_cppyy_package.py
rename to pypy/module/_cppyy/backend/create_cppyy_package.py
diff --git a/pypy/module/cppyy/bench/Makefile 
b/pypy/module/_cppyy/bench/Makefile
rename from pypy/module/cppyy/bench/Makefile
rename to pypy/module/_cppyy/bench/Makefile
diff --git a/pypy/module/cppyy/bench/bench02.cxx 
b/pypy/module/_cppyy/bench/bench02.cxx
rename from pypy/module/cppyy/bench/bench02.cxx
rename to pypy/module/_cppyy/bench/bench02.cxx
diff --git a/pypy/module/cppyy/bench/bench02.h 
b/pypy/module/_cppyy/bench/bench02.h
rename from pypy/module/cppyy/bench/bench02.h
rename to pypy/module/_cppyy/bench/bench02.h
diff --git a/pypy/module/cppyy/bench/bench02.xml 
b/pypy/module/_cppyy/bench/bench02.xml
rename from pypy/module/cppyy/bench/bench02.xml
rename to pypy/module/_cppyy/bench/bench02.xml
diff --git a/pypy/module/cppyy/bench/hsimple.C 
b/pypy/module/_cppyy/bench/hsimple.C
rename from pypy/module/cppyy/bench/hsimple.C
rename to pypy/module/_cppyy/bench/hsimple.C
diff --git a/pypy/module/cppyy/bench/hsimple.py 
b/pypy/module/_cppyy/bench/hsimple.py
rename from pypy/module/cppyy/bench/hsimple.py
rename to pypy/module/_cppyy/bench/hsimple.py
diff --git a/pypy/module/cppyy/bench/hsimple_rflx.py 
b/pypy/module/_cppyy/bench/hsimple_rflx.py
rename from pypy/module/cppyy/bench/hsimple_rflx.py
rename to pypy/module/_cppyy/bench/hsimple_rflx.py
diff --git a/pypy/module/cppyy/capi/__init__.py 
b/pypy/module/_cppyy/capi/__init__.py
rename from pypy/module/cppyy/capi/__init__.py
rename to pypy/module/_cppyy/capi/__init__.py
--- a/pypy/module/cppyy/capi/__init__.py
+++ b/pypy/module/_cppyy/capi/__init__.py
@@ -9,10 +9,10 @@
 # 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,\
+from pypy.module._cppyy.capi.capi_types import C_OBJECT,\
     C_NULL_TYPE, C_NULL_OBJECT
 
 def direct_ptradd(ptr, offset):
diff --git a/pypy/module/cppyy/capi/builtin_capi.py 
b/pypy/module/_cppyy/capi/builtin_capi.py
rename from pypy/module/cppyy/capi/builtin_capi.py
rename to pypy/module/_cppyy/capi/builtin_capi.py
--- a/pypy/module/cppyy/capi/builtin_capi.py
+++ b/pypy/module/_cppyy/capi/builtin_capi.py
@@ -4,7 +4,7 @@
 
 import cling_capi as backend
 
-from pypy.module.cppyy.capi.capi_types import C_SCOPE, C_TYPE, C_OBJECT,\
+from pypy.module._cppyy.capi.capi_types import C_SCOPE, C_TYPE, C_OBJECT,\
    C_METHOD, C_INDEX, C_INDEX_ARRAY, WLAVC_INDEX, C_FUNC_PTR
 
 identify  = backend.identify
diff --git a/pypy/module/cppyy/capi/capi_types.py 
b/pypy/module/_cppyy/capi/capi_types.py
rename from pypy/module/cppyy/capi/capi_types.py
rename to pypy/module/_cppyy/capi/capi_types.py
diff --git a/pypy/module/cppyy/capi/cling_capi.py 
b/pypy/module/_cppyy/capi/cling_capi.py
rename from pypy/module/cppyy/capi/cling_capi.py
rename to pypy/module/_cppyy/capi/cling_capi.py
--- a/pypy/module/cppyy/capi/cling_capi.py
+++ b/pypy/module/_cppyy/capi/cling_capi.py
@@ -11,7 +11,7 @@
 from rpython.rlib import jit, libffi, rdynload
 
 from pypy.module._rawffi.array import W_ArrayInstance
-from pypy.module.cppyy.capi.capi_types import C_OBJECT
+from pypy.module._cppyy.capi.capi_types import C_OBJECT
 
 __all__ = ['identify', 'std_string_name', 'eci', 'c_load_dictionary']
 
@@ -99,7 +99,7 @@
 def stdstring_c_str(space, w_self):
     """Return a python string taking into account \0"""
 
-    from pypy.module.cppyy import interp_cppyy
+    from pypy.module._cppyy import interp_cppyy
     cppstr = space.interp_w(interp_cppyy.W_CPPInstance, w_self, 
can_be_None=False)
     return space.wrap(c_stdstring2charp(space, cppstr._rawobject))
 
@@ -112,12 +112,12 @@
         W_AbstractSeqIterObject.__init__(self, w_vector)
         # TODO: this should live in rpythonize.py or something so that the
         # imports can move to the top w/o getting circles
-        from pypy.module.cppyy import interp_cppyy
+        from pypy.module._cppyy import interp_cppyy
         assert isinstance(w_vector, interp_cppyy.W_CPPInstance)
         vector = space.interp_w(interp_cppyy.W_CPPInstance, w_vector)
         self.overload = vector.cppclass.get_overload("__getitem__")
 
-        from pypy.module.cppyy import capi
+        from pypy.module._cppyy import capi
         v_type = capi.c_stdvector_valuetype(space, vector.cppclass.name)
         v_size = capi.c_stdvector_valuesize(space, vector.cppclass.name)
 
@@ -131,7 +131,7 @@
 
         self.data = rffi.cast(rffi.VOIDP, space.uint_w(arr.getbuffer(space)))
 
-        from pypy.module.cppyy import converter
+        from pypy.module._cppyy import converter
         self.converter = converter.get_converter(space, v_type, '')
         self.len     = 
space.uint_w(vector.cppclass.get_overload("size").call(w_vector, []))
         self.stride  = v_size
@@ -143,7 +143,7 @@
             self.w_seq = None
             raise OperationError(space.w_StopIteration, space.w_None)
         try:
-            from pypy.module.cppyy import capi    # TODO: refector
+            from pypy.module._cppyy import capi   # TODO: refector
             offset = capi.direct_ptradd(rffi.cast(C_OBJECT, self.data), 
self.index*self.stride)
             w_item = self.converter.from_memory(space, space.w_None, 
space.w_None, offset)
         except OperationError as e:
@@ -186,7 +186,7 @@
         _method_alias(space, w_pycppclass, "__str__",           "c_str")
 
     if "vector" in name[:11]: # len('std::vector') == 11
-        from pypy.module.cppyy import capi
+        from pypy.module._cppyy import capi
         v_type = capi.c_stdvector_valuetype(space, name)
         if v_type:
             space.setattr(w_pycppclass, space.wrap("value_type"), 
space.wrap(v_type))
diff --git a/pypy/module/_cppyy/capi/loadable_capi.py 
b/pypy/module/_cppyy/capi/loadable_capi.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cppyy/capi/loadable_capi.py
@@ -0,0 +1,629 @@
+from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib.rarithmetic import intmask
+from rpython.rlib import jit, jit_libffi, libffi, rdynload, objectmodel
+from rpython.rlib.rarithmetic import r_singlefloat
+from rpython.tool import leakfinder
+
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.error import oefmt
+
+from pypy.module._cffi_backend import ctypefunc, ctypeprim, cdataobj, misc
+from pypy.module._cffi_backend import newtype
+from pypy.module._cppyy import ffitypes
+
+from pypy.module._cppyy.capi.capi_types import C_SCOPE, C_TYPE, C_OBJECT,\
+   C_METHOD, C_INDEX, C_INDEX_ARRAY, WLAVC_INDEX, C_FUNC_PTR
+
+
+reflection_library = 'libcppyy_backend.so'
+
+def identify():
+    return 'loadable_capi'
+
+# this is not technically correct, but will do for now
+std_string_name = 'std::basic_string<char>'
+
+class _Arg:         # poor man's union
+    _immutable_ = True
+    def __init__(self, tc, h = 0, l = -1, s = '', p = rffi.cast(rffi.VOIDP, 
0)):
+        self.tc      = tc
+        self._handle = h
+        self._long   = l
+        self._string = s
+        self._voidp  = p
+
+class _ArgH(_Arg):
+    _immutable_ = True
+    def __init__(self, val):
+        _Arg.__init__(self, 'h', h = val)
+
+class _ArgL(_Arg):
+    _immutable_ = True
+    def __init__(self, val):
+        _Arg.__init__(self, 'l', l = val)
+
+class _ArgS(_Arg):
+    _immutable_ = True
+    def __init__(self, val):
+        _Arg.__init__(self, 's', s = val)
+
+class _ArgP(_Arg):
+    _immutable_ = True
+    def __init__(self, val):
+        _Arg.__init__(self, 'p', p = val)
+
+# 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 obj.tc == 'l':
+                    assert isinstance(argtype, 
ctypeprim.W_CTypePrimitiveSigned)
+                    misc.write_raw_signed_data(data, rffi.cast(rffi.LONG, 
obj._long), argtype.size)
+                elif obj.tc == 'h':
+                    assert isinstance(argtype, 
ctypeprim.W_CTypePrimitiveUnsigned)
+                    misc.write_raw_unsigned_data(data, rffi.cast(rffi.ULONG, 
obj._handle), argtype.size)
+                elif obj.tc == 'p':
+                    assert obj._voidp != rffi.cast(rffi.VOIDP, 0)
+                    data = rffi.cast(rffi.VOIDPP, data)
+                    data[0] = obj._voidp
+                else:    # only other use is sring
+                    assert obj.tc == 's'
+                    n = len(obj._string)
+                    assert raw_string == rffi.cast(rffi.CCHARP, 0)
+                    # XXX could use rffi.get_nonmovingbuffer_final_null()
+                    raw_string = rffi.str2charp(obj._string)
+                    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)
+            # this wrapping is unnecessary, but the assumption is that given 
the
+            # immediate unwrapping, the round-trip is removed
+            w_res = self.ctitem.copy_and_convert_to_object(resultdata)
+        finally:
+            if raw_string != rffi.cast(rffi.CCHARP, 0):
+                rffi.free_charp(raw_string)
+            lltype.free(buffer, flavor='raw')
+        return w_res
+
+class State(object):
+    def __init__(self, space):
+        self.library = None
+        self.capi_calls = {}
+
+        nt = newtype     # module from _cffi_backend
+        state = space.fromcache(ffitypes.State)   # factored out common types
+
+        # TODO: the following need to match up with the globally defined C_XYZ 
low-level
+        # types (see capi/__init__.py), but by using strings here, that isn't 
guaranteed
+        c_opaque_ptr = state.c_ulong
+ 
+        c_scope       = c_opaque_ptr
+        c_type        = c_scope
+        c_object      = c_opaque_ptr
+        c_method      = c_opaque_ptr
+        c_index       = state.c_long
+        c_index_array = state.c_voidp
+
+        c_void    = state.c_void
+        c_char    = state.c_char
+        c_uchar   = state.c_uchar
+        c_short   = state.c_short
+        c_int     = state.c_int
+        c_long    = state.c_long
+        c_llong   = state.c_llong
+        c_ullong  = state.c_ullong
+        c_float   = state.c_float
+        c_double  = state.c_double
+        c_ldouble = state.c_ldouble
+
+        c_ccharp = state.c_ccharp
+        c_voidp  = state.c_voidp
+
+        c_size_t = nt.new_primitive_type(space, 'size_t')
+        c_ptrdiff_t = nt.new_primitive_type(space, 'ptrdiff_t')
+
+        self.capi_call_ifaces = {
+            # name to opaque C++ scope representation
+            'num_scopes'               : ([c_scope],                  c_int),
+            'scope_name'               : ([c_scope, c_int],           
c_ccharp),
+
+            'resolve_name'             : ([c_ccharp],                 
c_ccharp),
+            'get_scope'                : ([c_ccharp],                 c_scope),
+            'actual_class'             : ([c_type, c_object],         c_type),
+
+            # memory management
+            'allocate'                 : ([c_type],                   
c_object),
+            'deallocate'               : ([c_type, c_object],         c_void),
+            'destruct'                 : ([c_type, c_object],         c_void),
+
+            # method/function dispatching
+            'call_v'       : ([c_method, c_object, c_int, c_voidp],   c_void),
+            'call_b'       : ([c_method, c_object, c_int, c_voidp],   c_uchar),
+            'call_c'       : ([c_method, c_object, c_int, c_voidp],   c_char),
+
+            'call_h'       : ([c_method, c_object, c_int, c_voidp],   c_short),
+            'call_i'       : ([c_method, c_object, c_int, c_voidp],   c_int),
+            'call_l'       : ([c_method, c_object, c_int, c_voidp],   c_long),
+            'call_ll'      : ([c_method, c_object, c_int, c_voidp],   c_llong),
+            'call_f'       : ([c_method, c_object, c_int, c_voidp],   c_float),
+            'call_d'       : ([c_method, c_object, c_int, c_voidp],   
c_double),
+            'call_ld'      : ([c_method, c_object, c_int, c_voidp],   
c_ldouble),
+
+            'call_r'       : ([c_method, c_object, c_int, c_voidp],   c_voidp),
+            # call_s actually takes an size_t* as last parameter, but this 
will do
+            'call_s'       : ([c_method, c_object, c_int, c_voidp, c_voidp],   
 c_ccharp),
+
+            '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_function_address'     : ([c_scope, c_index],         
c_voidp), # TODO: verify
+
+            # handling of function argument buffer
+            'allocate_function_args'   : ([c_int],                    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_template'              : ([c_ccharp],                 c_int),
+            'is_abstract'              : ([c_type],                   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_ptrdiff_t),
+
+            # 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_req_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_is_template'       : ([c_scope, c_index],         c_int),
+            'method_num_template_args' : ([c_scope, c_index],         c_int),
+            'method_template_arg_name' : ([c_scope, c_index, c_index],         
 c_ccharp),
+
+            'get_method'               : ([c_scope, c_index],         
c_method),
+            'get_global_operator'      : ([c_scope, c_scope, c_scope, 
c_ccharp],   c_index),
+
+            # method properties
+            'is_constructor'           : ([c_type, c_index],          c_int),
+            'is_staticmethod'          : ([c_type, c_index],          c_int),
+
+            # data member reflection information
+            'num_datamembers'          : ([c_scope],                  c_int),
+            'datamember_name'          : ([c_scope, c_int],           
c_ccharp),
+            'datamember_type'          : ([c_scope, c_int],           
c_ccharp),
+            'datamember_offset'        : ([c_scope, c_int],           
c_ptrdiff_t),
+
+            'datamember_index'         : ([c_scope, c_ccharp],        c_int),
+
+            # data member properties
+            'is_publicdata'            : ([c_scope, c_int],           c_int),
+            'is_staticdata'            : ([c_scope, c_int],           c_int),
+
+            # misc helpers
+            'strtoll'                  : ([c_ccharp],                 c_llong),
+            'strtoull'                 : ([c_ccharp],                 
c_ullong),
+            'free'                     : ([c_voidp],                  c_void),
+
+            'charp2stdstring'          : ([c_ccharp, c_size_t],       
c_object),
+            #stdstring2charp  actually takes an size_t* as last parameter, but 
this will do
+            'stdstring2charp'          : ([c_object, c_voidp],        
c_ccharp),
+            'stdstring2stdstring'      : ([c_object],                 
c_object),
+
+            'stdvector_valuetype'      : ([c_ccharp],                 
c_ccharp),
+            'stdvector_valuesize'      : ([c_ccharp],                 
c_size_t),
+
+        }
+
+        # size/offset are backend-specific but fixed after load
+        self.c_sizeof_farg = 0
+        self.c_offset_farg = 0
+
+
+def load_reflection_library(space):
+    state = space.fromcache(State)
+    if state.library is None:
+        from pypy.module._cffi_backend.libraryobj import W_Library
+        state.library = W_Library(space, reflection_library, 
rdynload.RTLD_LOCAL | rdynload.RTLD_LAZY)
+        if state.library:
+            # fix constants
+            state.c_sizeof_farg = _cdata_to_size_t(space, call_capi(space, 
'function_arg_sizeof', []))
+            state.c_offset_farg = _cdata_to_size_t(space, call_capi(space, 
'function_arg_typeoffset', []))
+    return state.library
+
+def verify_backend(space):
+    try:
+        load_reflection_library(space)
+    except Exception:
+        if objectmodel.we_are_translated():
+            raise oefmt(space.w_ImportError,
+                        "missing reflection library %s", reflection_library)
+        return False
+    return True
+
+def call_capi(space, name, args):
+    state = space.fromcache(State)
+    try:
+        c_call = state.capi_calls[name]
+    except KeyError:
+        if state.library is None:
+            load_reflection_library(space)
+        iface = state.capi_call_ifaces[name]
+        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
+    with c_call as ptr:
+        return c_call.ctype.rcall(ptr, args)
+
+def _cdata_to_cobject(space, w_cdata):
+    return rffi.cast(C_OBJECT, space.uint_w(w_cdata))
+
+def _cdata_to_size_t(space, w_cdata):
+    return rffi.cast(rffi.SIZE_T, space.uint_w(w_cdata))
+
+def _cdata_to_ptrdiff_t(space, w_cdata):
+    return rffi.cast(rffi.LONG, space.int_w(w_cdata))
+
+def _cdata_to_ptr(space, w_cdata): # TODO: this is both a hack and dreadfully 
slow
+    w_cdata = space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False)
+    ptr = w_cdata.unsafe_escaping_ptr()
+    return rffi.cast(rffi.VOIDP, ptr)
+
+def _cdata_to_ccharp(space, w_cdata):
+    ptr = _cdata_to_ptr(space, w_cdata)      # see above ... something better?
+    return rffi.cast(rffi.CCHARP, ptr)
+
+def c_load_dictionary(name):
+    return libffi.CDLL(name)
+
+# name to opaque C++ scope representation ------------------------------------
+def c_num_scopes(space, cppscope):
+    return space.int_w(call_capi(space, 'num_scopes', 
[_ArgH(cppscope.handle)]))
+def c_scope_name(space, cppscope, iscope):
+    args = [_ArgH(cppscope.handle), _ArgL(iscope)]
+    return charp2str_free(space, call_capi(space, 'scope_name', args))
+
+def c_resolve_name(space, name):
+    return charp2str_free(space, call_capi(space, 'resolve_name', 
[_ArgS(name)]))
+def c_get_scope_opaque(space, name):
+    return rffi.cast(C_SCOPE, space.uint_w(call_capi(space, 'get_scope', 
[_ArgS(name)])))
+def c_actual_class(space, cppclass, cppobj):
+    args = [_ArgH(cppclass.handle), _ArgH(cppobj)]
+    return rffi.cast(C_TYPE, space.uint_w(call_capi(space, 'actual_class', 
args)))
+
+# memory management ----------------------------------------------------------
+def c_allocate(space, cppclass):
+    return _cdata_to_cobject(space, call_capi(space, 'allocate', 
[_ArgH(cppclass.handle)]))
+def c_deallocate(space, cppclass, cppobject):
+    call_capi(space, 'deallocate', [_ArgH(cppclass.handle), _ArgH(cppobject)])
+def c_destruct(space, cppclass, cppobject):
+    call_capi(space, 'destruct', [_ArgH(cppclass.handle), _ArgH(cppobject)])
+
+# method/function dispatching ------------------------------------------------
+def c_call_v(space, cppmethod, cppobject, nargs, cargs):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
+    call_capi(space, 'call_v', args)
+def c_call_b(space, cppmethod, cppobject, nargs, cargs):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
+    return rffi.cast(rffi.UCHAR, space.c_uint_w(call_capi(space, 'call_b', 
args)))
+def c_call_c(space, cppmethod, cppobject, nargs, cargs):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
+    return rffi.cast(rffi.CHAR, space.bytes_w(call_capi(space, 'call_c', 
args))[0])
+def c_call_h(space, cppmethod, cppobject, nargs, cargs):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
+    return rffi.cast(rffi.SHORT, space.int_w(call_capi(space, 'call_h', args)))
+def c_call_i(space, cppmethod, cppobject, nargs, cargs):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
+    return rffi.cast(rffi.INT, space.c_int_w(call_capi(space, 'call_i', args)))
+def c_call_l(space, cppmethod, cppobject, nargs, cargs):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
+    return rffi.cast(rffi.LONG, space.int_w(call_capi(space, 'call_l', args)))
+def c_call_ll(space, cppmethod, cppobject, nargs, cargs):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
+    return rffi.cast(rffi.LONGLONG, space.r_longlong_w(call_capi(space, 
'call_ll', args)))
+def c_call_f(space, cppmethod, cppobject, nargs, cargs):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
+    return rffi.cast(rffi.FLOAT, r_singlefloat(space.float_w(call_capi(space, 
'call_f', args))))
+def c_call_d(space, cppmethod, cppobject, nargs, cargs):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
+    return rffi.cast(rffi.DOUBLE, space.float_w(call_capi(space, 'call_d', 
args)))
+def c_call_ld(space, cppmethod, cppobject, nargs, cargs):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
+    return rffi.cast(rffi.LONGDOUBLE, space.float_w(call_capi(space, 
'call_ld', args)))
+
+def c_call_r(space, cppmethod, cppobject, nargs, cargs):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
+    return _cdata_to_ptr(space, call_capi(space, 'call_r', args))
+def c_call_s(space, cppmethod, cppobject, nargs, cargs):
+    length = lltype.malloc(rffi.SIZE_TP.TO, 1, flavor='raw')
+    try:
+        w_cstr = call_capi(space, 'call_s',
+            [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs),
+             _ArgP(rffi.cast(rffi.VOIDP, length))])
+        cstr_len = intmask(length[0])
+    finally:
+        lltype.free(length, flavor='raw')
+    return _cdata_to_ccharp(space, w_cstr), cstr_len
+
+def c_constructor(space, cppmethod, cppobject, nargs, cargs):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
+    return _cdata_to_cobject(space, call_capi(space, 'constructor', args))
+def c_call_o(space, cppmethod, cppobject, nargs, cargs, cppclass):
+    args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs), 
_ArgH(cppclass.handle)]
+    return _cdata_to_cobject(space, call_capi(space, 'call_o', args))
+
+def c_get_function_address(space, cppscope, index):
+    args = [_ArgH(cppscope.handle), _ArgL(index)]
+    return rffi.cast(C_FUNC_PTR,
+        _cdata_to_ptr(space, call_capi(space, 'get_function_address', args)))
+
+# handling of function argument buffer ---------------------------------------
+def c_allocate_function_args(space, size):
+    return _cdata_to_ptr(space, call_capi(space, 'allocate_function_args', 
[_ArgL(size)]))
+def c_deallocate_function_args(space, cargs):
+    call_capi(space, 'deallocate_function_args', [_ArgP(cargs)])
+def c_function_arg_sizeof(space):
+    state = space.fromcache(State)
+    return state.c_sizeof_farg
+def c_function_arg_typeoffset(space):
+    state = space.fromcache(State)
+    return state.c_offset_farg
+
+# scope reflection information -----------------------------------------------
+def c_is_namespace(space, scope):
+    return space.bool_w(call_capi(space, 'is_namespace', [_ArgH(scope)]))
+def c_is_template(space, name):
+    return space.bool_w(call_capi(space, 'is_template', [_ArgS(name)]))
+def c_is_abstract(space, cpptype):
+    return space.bool_w(call_capi(space, 'is_abstract', [_ArgH(cpptype)]))
+def c_is_enum(space, name):
+    return space.bool_w(call_capi(space, 'is_enum', [_ArgS(name)]))
+
+# type/class reflection information ------------------------------------------
+def c_final_name(space, cpptype):
+    return charp2str_free(space, call_capi(space, 'final_name', 
[_ArgH(cpptype)]))
+def c_scoped_final_name(space, cpptype):
+    return charp2str_free(space, call_capi(space, 'scoped_final_name', 
[_ArgH(cpptype)]))
+def c_has_complex_hierarchy(space, handle):
+    return space.bool_w(call_capi(space, 'has_complex_hierarchy', 
[_ArgH(handle)]))
+def c_num_bases(space, cppclass):
+    return space.int_w(call_capi(space, 'num_bases', [_ArgH(cppclass.handle)]))
+def c_base_name(space, cppclass, base_index):
+    args = [_ArgH(cppclass.handle), _ArgL(base_index)]
+    return charp2str_free(space, call_capi(space, 'base_name', args))
+def c_is_subtype(space, derived, base):
+    jit.promote(base)
+    if derived == base:
+        return bool(1)
+    return space.bool_w(call_capi(space, 'is_subtype', [_ArgH(derived.handle), 
_ArgH(base.handle)]))
+
+def _c_base_offset(space, derived_h, base_h, address, direction):
+    args = [_ArgH(derived_h), _ArgH(base_h), _ArgH(address), _ArgL(direction)]
+    return _cdata_to_ptrdiff_t(space, call_capi(space, 'base_offset', args))
+def c_base_offset(space, derived, base, address, direction):
+    if derived == base:
+        return rffi.cast(rffi.LONG, 0)
+    return _c_base_offset(space, derived.handle, base.handle, address, 
direction)
+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 -------------------------------------
+def c_num_methods(space, cppscope):
+    args = [_ArgH(cppscope.handle)]
+    return space.int_w(call_capi(space, 'num_methods', args))
+def c_method_index_at(space, cppscope, imethod):
+    args = [_ArgH(cppscope.handle), _ArgL(imethod)]
+    return space.int_w(call_capi(space, 'method_index_at', args))
+def c_method_indices_from_name(space, cppscope, name):
+    args = [_ArgH(cppscope.handle), _ArgS(name)]
+    indices = rffi.cast(C_INDEX_ARRAY,
+                        _cdata_to_ptr(space, call_capi(space, 
'method_indices_from_name', args)))
+    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(space, rffi.cast(rffi.VOIDP, indices))   # c_free defined below
+    return py_indices
+
+def c_method_name(space, cppscope, index):
+    args = [_ArgH(cppscope.handle), _ArgL(index)]
+    return charp2str_free(space, call_capi(space, 'method_name', args))
+def c_method_result_type(space, cppscope, index):
+    args = [_ArgH(cppscope.handle), _ArgL(index)]
+    return charp2str_free(space, call_capi(space, 'method_result_type', args))
+def c_method_num_args(space, cppscope, index):
+    args = [_ArgH(cppscope.handle), _ArgL(index)]
+    return space.int_w(call_capi(space, 'method_num_args', args))
+def c_method_req_args(space, cppscope, index):
+    args = [_ArgH(cppscope.handle), _ArgL(index)]
+    return space.int_w(call_capi(space, 'method_req_args', args))
+def c_method_arg_type(space, cppscope, index, arg_index):
+    args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(arg_index)]
+    return charp2str_free(space, call_capi(space, 'method_arg_type', args))
+def c_method_arg_default(space, cppscope, index, arg_index):
+    args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(arg_index)]
+    return charp2str_free(space, call_capi(space, 'method_arg_default', args))
+def c_method_signature(space, cppscope, index):
+    args = [_ArgH(cppscope.handle), _ArgL(index)]
+    return charp2str_free(space, call_capi(space, 'method_signature', args))
+
+def c_method_is_template(space, cppscope, index):
+    args = [_ArgH(cppscope.handle), _ArgL(index)]
+    return space.bool_w(call_capi(space, 'method_is_template', args))
+def _c_method_num_template_args(space, cppscope, index):
+    args = [_ArgH(cppscope.handle), _ArgL(index)]
+    return space.int_w(call_capi(space, 'method_num_template_args', args)) 
+def c_template_args(space, cppscope, index):
+    nargs = _c_method_num_template_args(space, cppscope, index)
+    arg1 = _ArgH(cppscope.handle)
+    arg2 = _ArgL(index)
+    args = [c_resolve_name(space, charp2str_free(space,
+                call_capi(space, 'method_template_arg_name', [arg1, arg2, 
_ArgL(iarg)]))
+            ) for iarg in range(nargs)]
+    return args
+
+def c_get_method(space, cppscope, index):
+    args = [_ArgH(cppscope.handle), _ArgL(index)]
+    return rffi.cast(C_METHOD, space.uint_w(call_capi(space, 'get_method', 
args)))
+def c_get_global_operator(space, nss, lc, rc, op):
+    if nss is not None:
+        args = [_ArgH(nss.handle), _ArgH(lc.handle), _ArgH(rc.handle), 
_ArgS(op)]
+        return rffi.cast(WLAVC_INDEX, space.int_w(call_capi(space, 
'get_global_operator', args)))
+    return rffi.cast(WLAVC_INDEX, -1)
+
+# method properties ----------------------------------------------------------
+def c_is_constructor(space, cppclass, index):
+    args = [_ArgH(cppclass.handle), _ArgL(index)]
+    return space.bool_w(call_capi(space, 'is_constructor', args))
+def c_is_staticmethod(space, cppclass, index):
+    args = [_ArgH(cppclass.handle), _ArgL(index)]
+    return space.bool_w(call_capi(space, 'is_staticmethod', args))
+
+# data member reflection information -----------------------------------------
+def c_num_datamembers(space, cppscope):
+    return space.int_w(call_capi(space, 'num_datamembers', 
[_ArgH(cppscope.handle)]))
+def c_datamember_name(space, cppscope, datamember_index):
+    args = [_ArgH(cppscope.handle), _ArgL(datamember_index)]
+    return charp2str_free(space, call_capi(space, 'datamember_name', args))
+def c_datamember_type(space, cppscope, datamember_index):
+    args = [_ArgH(cppscope.handle), _ArgL(datamember_index)]
+    return  charp2str_free(space, call_capi(space, 'datamember_type', args))
+def c_datamember_offset(space, cppscope, datamember_index):
+    args = [_ArgH(cppscope.handle), _ArgL(datamember_index)]
+    return _cdata_to_ptrdiff_t(space, call_capi(space, 'datamember_offset', 
args))
+
+def c_datamember_index(space, cppscope, name):
+    args = [_ArgH(cppscope.handle), _ArgS(name)]
+    return space.int_w(call_capi(space, 'datamember_index', args))
+
+# data member properties -----------------------------------------------------
+def c_is_publicdata(space, cppscope, datamember_index):
+    args = [_ArgH(cppscope.handle), _ArgL(datamember_index)]
+    return space.bool_w(call_capi(space, 'is_publicdata', args))
+def c_is_staticdata(space, cppscope, datamember_index):
+    args = [_ArgH(cppscope.handle), _ArgL(datamember_index)]
+    return space.bool_w(call_capi(space, 'is_staticdata', args))
+
+# misc helpers ---------------------------------------------------------------
+def c_strtoll(space, svalue):
+    return space.r_longlong_w(call_capi(space, 'strtoll', [_ArgS(svalue)]))
+def c_strtoull(space, svalue):
+    return space.r_ulonglong_w(call_capi(space, 'strtoull', [_ArgS(svalue)]))
+def c_free(space, voidp):
+    call_capi(space, 'free', [_ArgP(voidp)])
+
+def charp2str_free(space, cdata):
+    charp = rffi.cast(rffi.CCHARP, _cdata_to_ptr(space, cdata))
+    pystr = rffi.charp2str(charp)
+    c_free(space, rffi.cast(rffi.VOIDP, charp))
+    return pystr
+
+def c_charp2stdstring(space, svalue, sz):
+    return _cdata_to_cobject(space, call_capi(space, 'charp2stdstring',
+        [_ArgS(svalue), _ArgH(rffi.cast(rffi.ULONG, sz))]))
+def c_stdstring2charp(space, cppstr):
+    sz = lltype.malloc(rffi.SIZE_TP.TO, 1, flavor='raw')
+    try:
+        w_cstr = call_capi(space, 'stdstring2charp',
+            [_ArgH(cppstr), _ArgP(rffi.cast(rffi.VOIDP, sz))])
+        cstr_len = intmask(sz[0])
+    finally:
+        lltype.free(sz, flavor='raw')
+    return rffi.charpsize2str(_cdata_to_ccharp(space, w_cstr), cstr_len)
+def c_stdstring2stdstring(space, cppobject):
+    return _cdata_to_cobject(space, call_capi(space, 'stdstring2stdstring', 
[_ArgH(cppobject)]))
+
+def c_stdvector_valuetype(space, pystr):
+    return charp2str_free(space, call_capi(space, 'stdvector_valuetype', 
[_ArgS(pystr)]))
+
+def c_stdvector_valuetype(space, pystr):
+    return charp2str_free(space, call_capi(space, 'stdvector_valuetype', 
[_ArgS(pystr)]))
+def c_stdvector_valuesize(space, pystr):
+    return _cdata_to_size_t(space, call_capi(space, 'stdvector_valuesize', 
[_ArgS(pystr)]))
+
+
+# TODO: factor these out ...
+# pythonizations
+def stdstring_c_str(space, w_self):
+    """Return a python string taking into account \0"""
+
+    from pypy.module._cppyy import interp_cppyy
+    cppstr = space.interp_w(interp_cppyy.W_CPPInstance, w_self, 
can_be_None=False)
+    return space.newtext(c_stdstring2charp(space, cppstr._rawobject))
+
+# setup pythonizations for later use at run-time
+_pythonizations = {}
+def register_pythonizations(space):
+    "NOT_RPYTHON"
+
+    allfuncs = [
+
+        ### std::string
+        stdstring_c_str,
+
+    ]
+
+    for f in allfuncs:
+        _pythonizations[f.__name__] = interp2app(f).spacebind(space)
+
+def _method_alias(space, w_pycppclass, m1, m2):
+    space.setattr(w_pycppclass, space.newtext(m1),
+                  space.getattr(w_pycppclass, space.newtext(m2)))
+
+def pythonize(space, name, w_pycppclass):
+    if name == "string":
+        space.setattr(w_pycppclass, space.newtext("c_str"), 
_pythonizations["stdstring_c_str"])
+        _method_alias(space, w_pycppclass, "_cppyy_as_builtin", "c_str")
+        _method_alias(space, w_pycppclass, "__str__",           "c_str")
diff --git a/pypy/module/_cppyy/converter.py b/pypy/module/_cppyy/converter.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cppyy/converter.py
@@ -0,0 +1,893 @@
+import sys
+
+from pypy.interpreter.error import OperationError, oefmt
+
+from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib.rarithmetic import r_singlefloat, r_longfloat
+from rpython.rlib import rfloat
+
+from pypy.module._rawffi.interp_rawffi import letter2tp
+from pypy.module._rawffi.array import W_Array, W_ArrayInstance
+
+from pypy.module._cppyy import helper, capi, ffitypes
+
+# Converter objects are used to translate between RPython and C++. They are
+# defined by the type name for which they provide conversion. Uses are for
+# function arguments, as well as for read and write access to data members.
+# All type conversions are fully checked.
+#
+# Converter instances are greated by get_converter(<type name>), see below.
+# The name given should be qualified in case there is a specialised, exact
+# match for the qualified type.
+
+
+def get_rawobject(space, w_obj):
+    from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+    cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+    if cppinstance:
+        rawobject = cppinstance.get_rawobject()
+        assert lltype.typeOf(rawobject) == capi.C_OBJECT
+        return rawobject
+    return capi.C_NULL_OBJECT
+
+def set_rawobject(space, w_obj, address):
+    from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+    cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+    if cppinstance:
+        assert lltype.typeOf(cppinstance._rawobject) == capi.C_OBJECT
+        cppinstance._rawobject = rffi.cast(capi.C_OBJECT, address)
+
+def get_rawobject_nonnull(space, w_obj):
+    from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+    cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+    if cppinstance:
+        cppinstance._nullcheck()
+        rawobject = cppinstance.get_rawobject()
+        assert lltype.typeOf(rawobject) == capi.C_OBJECT
+        return rawobject
+    return capi.C_NULL_OBJECT
+
+def is_nullpointer_specialcase(space, w_obj):
+    # 0, None, and nullptr may serve as "NULL", check for any of them
+
+    # integer 0
+    try:
+        return space.int_w(w_obj) == 0
+    except Exception:
+        pass
+    # None or nullptr
+    from pypy.module._cppyy import interp_cppyy
+    return space.is_true(space.is_(w_obj, space.w_None)) or \
+        space.is_true(space.is_(w_obj, interp_cppyy.get_nullptr(space)))
+
+def get_rawbuffer(space, w_obj):
+    # raw buffer
+    try:
+        buf = space.getarg_w('s*', w_obj)
+        return rffi.cast(rffi.VOIDP, buf.get_raw_address())
+    except Exception:
+        pass
+    # array type
+    try:
+        arr = space.interp_w(W_ArrayInstance, w_obj, can_be_None=True)
+        if arr:
+            return rffi.cast(rffi.VOIDP, space.uint_w(arr.getbuffer(space)))
+    except Exception:
+        pass
+    # pre-defined NULL
+    if is_nullpointer_specialcase(space, w_obj):
+        return rffi.cast(rffi.VOIDP, 0)
+    raise TypeError("not an addressable buffer")
+
+
+class TypeConverter(object):
+    _immutable_fields_ = ['cffi_name', 'uses_local', 'name']
+
+    cffi_name  = None
+    uses_local = False
+    name       = ""
+
+    def __init__(self, space, extra):
+        pass
+
+    def _get_raw_address(self, space, w_obj, offset):
+        rawobject = get_rawobject_nonnull(space, w_obj)
+        assert lltype.typeOf(rawobject) == capi.C_OBJECT
+        if rawobject:
+            fieldptr = capi.direct_ptradd(rawobject, offset)
+        else:
+            fieldptr = rffi.cast(capi.C_OBJECT, offset)
+        return fieldptr
+
+    def _is_abstract(self, space):
+        raise oefmt(space.w_TypeError,
+                    "no converter available for '%s'", self.name)
+
+    def cffi_type(self, space):
+        from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        self._is_abstract(space)
+
+    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, address):
+        from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        self._is_abstract(space)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        self._is_abstract(space)
+
+    def finalize_call(self, space, w_obj, call_local):
+        pass
+
+    def free_argument(self, space, arg, call_local):
+        pass
+
+
+class ArrayCache(object):
+    def __init__(self, space):
+        self.space = space
+    def __getattr__(self, name):
+        if name.startswith('array_'):
+            typecode = name[len('array_'):]
+            arr = self.space.interp_w(W_Array, letter2tp(self.space, typecode))
+            setattr(self, name, arr)
+            return arr
+        raise AttributeError(name)
+
+    def _freeze_(self):
+        return True
+
+class ArrayTypeConverterMixin(object):
+    _mixin_ = True
+    _immutable_fields_ = ['size']
+
+    def __init__(self, space, array_size):
+        if array_size <= 0:
+            self.size = sys.maxint
+        else:
+            self.size = array_size
+
+    def cffi_type(self, space):
+        state = space.fromcache(ffitypes.State)
+        return state.c_voidp
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        # read access, so no copy needed
+        address_value = self._get_raw_address(space, w_obj, offset)
+        address = rffi.cast(rffi.ULONG, address_value)
+        cache = space.fromcache(ArrayCache)
+        arr = getattr(cache, 'array_' + self.typecode)
+        return arr.fromaddress(space, address, self.size)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        # copy the full array (uses byte copy for now)
+        address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, 
offset))
+        buf = space.getarg_w('s*', w_value)
+        # TODO: report if too many items given?
+        for i in range(min(self.size*self.typesize, buf.getlength())):
+            address[i] = buf.getitem(i)
+
+
+class PtrTypeConverterMixin(object):
+    _mixin_ = True
+    _immutable_fields_ = ['size']
+
+    def __init__(self, space, array_size):
+        self.size = sys.maxint
+
+    def cffi_type(self, space):
+        state = space.fromcache(ffitypes.State)
+        return state.c_voidp
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        w_tc = space.findattr(w_obj, space.newtext('typecode'))
+        if w_tc is not None and space.text_w(w_tc) != self.typecode:
+            raise oefmt(space.w_TypeError,
+                        "expected %s pointer type, but received %s",
+                        self.typecode, space.text_w(w_tc))
+        x = rffi.cast(rffi.VOIDPP, address)
+        try:
+            x[0] = rffi.cast(rffi.VOIDP, get_rawbuffer(space, w_obj))
+        except TypeError:
+            raise oefmt(space.w_TypeError,
+                        "raw buffer interface not supported")
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset(space)] = 'o'
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        # read access, so no copy needed
+        address_value = self._get_raw_address(space, w_obj, offset)
+        address = rffi.cast(rffi.ULONGP, address_value)
+        cache = space.fromcache(ArrayCache)
+        arr = getattr(cache, 'array_' + self.typecode)
+        return arr.fromaddress(space, address[0], self.size)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        # copy only the pointer value
+        rawobject = get_rawobject_nonnull(space, w_obj)
+        byteptr = rffi.cast(rffi.CCHARPP, capi.direct_ptradd(rawobject, 
offset))
+        buf = space.getarg_w('s*', w_value)
+        try:
+            byteptr[0] = buf.get_raw_address()
+        except ValueError:
+            raise oefmt(space.w_TypeError,
+                        "raw buffer interface not supported")
+
+
+class NumericTypeConverterMixin(object):
+    _mixin_ = True
+
+    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, 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)
+        rffiptr = rffi.cast(self.c_ptrtype, address)
+        return self._wrap_object(space, rffiptr[0])
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        address = self._get_raw_address(space, w_obj, offset)
+        rffiptr = rffi.cast(self.c_ptrtype, address)
+        rffiptr[0] = self._unwrap_object(space, w_value)
+
+class ConstRefNumericTypeConverterMixin(NumericTypeConverterMixin):
+    _mixin_ = True
+    _immutable_fields_ = ['uses_local']
+
+    uses_local = True
+
+    def cffi_type(self, space):
+        state = space.fromcache(ffitypes.State)
+        return state.c_voidp
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to