[pypy-commit] pypy arm-backend-2: merge default

bivab noreply at buildbot.pypy.org
Fri Jun 29 11:14:22 CEST 2012


Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r55870:eeb247a70b02
Date: 2012-06-29 11:12 +0200
http://bitbucket.org/pypy/pypy/changeset/eeb247a70b02/

Log:	merge default

diff too long, truncating to 10000 out of 21315 lines

diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -21,6 +21,16 @@
 ^pypy/module/cpyext/test/.+\.obj$
 ^pypy/module/cpyext/test/.+\.manifest$
 ^pypy/module/test_lib_pypy/ctypes_tests/.+\.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/doc/.+\.html$
 ^pypy/doc/config/.+\.rst$
 ^pypy/doc/basicblock\.asc$
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -216,6 +216,7 @@
     DFKI GmbH, Germany 
     Impara, Germany
     Change Maker, Sweden 
+    University of California Berkeley, USA
 
 The PyPy Logo as used by http://speed.pypy.org and others was created
 by Samuel Reis and is distributed on terms of Creative Commons Share Alike
diff --git a/ctypes_configure/cbuild.py b/ctypes_configure/cbuild.py
--- a/ctypes_configure/cbuild.py
+++ b/ctypes_configure/cbuild.py
@@ -372,7 +372,7 @@
         self.library_dirs = list(eci.library_dirs)
         self.compiler_exe = compiler_exe
         self.profbased = profbased
-        if not sys.platform in ('win32', 'darwin'): # xxx
+        if not sys.platform in ('win32', 'darwin', 'cygwin'): # xxx
             if 'm' not in self.libraries:
                 self.libraries.append('m')
             if 'pthread' not in self.libraries:
diff --git a/lib-python/2.7/ctypes/__init__.py b/lib-python/2.7/ctypes/__init__.py
--- a/lib-python/2.7/ctypes/__init__.py
+++ b/lib-python/2.7/ctypes/__init__.py
@@ -351,7 +351,10 @@
         self._FuncPtr = _FuncPtr
 
         if handle is None:
-            self._handle = _ffi.CDLL(name, mode)
+            if flags & _FUNCFLAG_CDECL:
+                self._handle = _ffi.CDLL(name, mode)
+            else:
+                self._handle = _ffi.WinDLL(name, mode)
         else:
             self._handle = handle
 
diff --git a/lib-python/2.7/distutils/sysconfig_pypy.py b/lib-python/2.7/distutils/sysconfig_pypy.py
--- a/lib-python/2.7/distutils/sysconfig_pypy.py
+++ b/lib-python/2.7/distutils/sysconfig_pypy.py
@@ -39,11 +39,10 @@
     If 'prefix' is supplied, use it instead of sys.prefix or
     sys.exec_prefix -- i.e., ignore 'plat_specific'.
     """
-    if standard_lib:
-        raise DistutilsPlatformError(
-            "calls to get_python_lib(standard_lib=1) cannot succeed")
     if prefix is None:
         prefix = PREFIX
+    if standard_lib:
+        return os.path.join(prefix, "lib-python", get_python_version())
     return os.path.join(prefix, 'site-packages')
 
 
diff --git a/lib-python/2.7/pickle.py b/lib-python/2.7/pickle.py
--- a/lib-python/2.7/pickle.py
+++ b/lib-python/2.7/pickle.py
@@ -638,7 +638,7 @@
             # else tmp is empty, and we're done
 
     def save_dict(self, obj):
-        modict_saver = self._pickle_moduledict(obj)
+        modict_saver = self._pickle_maybe_moduledict(obj)
         if modict_saver is not None:
             return self.save_reduce(*modict_saver)
 
@@ -691,26 +691,20 @@
                 write(SETITEM)
             # else tmp is empty, and we're done
 
-    def _pickle_moduledict(self, obj):
+    def _pickle_maybe_moduledict(self, obj):
         # save module dictionary as "getattr(module, '__dict__')"
+        try:
+            name = obj['__name__']
+            if type(name) is not str:
+                return None
+            themodule = sys.modules[name]
+            if type(themodule) is not ModuleType:
+                return None
+            if themodule.__dict__ is not obj:
+                return None
+        except (AttributeError, KeyError, TypeError):
+            return None
 
-        # build index of module dictionaries
-        try:
-            modict = self.module_dict_ids
-        except AttributeError:
-            modict = {}
-            from sys import modules
-            for mod in modules.values():
-                if isinstance(mod, ModuleType):
-                    modict[id(mod.__dict__)] = mod
-            self.module_dict_ids = modict
-
-        thisid = id(obj)
-        try:
-            themodule = modict[thisid]
-        except KeyError:
-            return None
-        from __builtin__ import getattr
         return getattr, (themodule, '__dict__')
 
 
diff --git a/lib-python/stdlib-upgrade.txt b/lib-python/stdlib-upgrade.txt
new file mode 100644
--- /dev/null
+++ b/lib-python/stdlib-upgrade.txt
@@ -0,0 +1,19 @@
+Process for upgrading the stdlib to a new cpython version
+==========================================================
+
+.. note::
+
+    overly detailed
+
+1. check out the branch vendor/stdlib
+2. upgrade the files there
+3. update stdlib-versions.txt with the output of hg -id from the cpython repo
+4. commit
+5. update to default/py3k
+6. create a integration branch for the new stdlib
+   (just hg branch stdlib-$version)
+7. merge vendor/stdlib
+8. commit
+10. fix issues
+11. commit --close-branch
+12. merge to default
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -47,10 +47,6 @@
         else:
             return self.from_param(as_parameter)
 
-    def get_ffi_param(self, value):
-        cdata = self.from_param(value)
-        return cdata, cdata._to_ffi_param()
-
     def get_ffi_argtype(self):
         if self._ffiargtype:
             return self._ffiargtype
diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -391,7 +391,7 @@
         address = self._get_address()
         ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
         ffires = restype.get_ffi_argtype()
-        return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires)
+        return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires, self._flags_)
 
     def _getfuncptr(self, argtypes, restype, thisarg=None):
         if self._ptr is not None and (argtypes is self._argtypes_ or argtypes == self._argtypes_):
@@ -412,7 +412,7 @@
             ptr = thisarg[0][self._com_index - 0x1000]
             ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
             ffires = restype.get_ffi_argtype()
-            return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires)
+            return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires, self._flags_)
         
         cdll = self.dll._handle
         try:
@@ -444,10 +444,6 @@
 
     @classmethod
     def _conv_param(cls, argtype, arg):
-        if isinstance(argtype, _CDataMeta):
-            cobj, ffiparam = argtype.get_ffi_param(arg)
-            return cobj, ffiparam, argtype
-        
         if argtype is not None:
             arg = argtype.from_param(arg)
         if hasattr(arg, '_as_parameter_'):
diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py
--- a/lib_pypy/_ctypes/primitive.py
+++ b/lib_pypy/_ctypes/primitive.py
@@ -249,6 +249,13 @@
                 self._buffer[0] = value
             result.value = property(_getvalue, _setvalue)
 
+        elif tp == '?':  # regular bool
+            def _getvalue(self):
+                return bool(self._buffer[0])
+            def _setvalue(self, value):
+                self._buffer[0] = bool(value)
+            result.value = property(_getvalue, _setvalue)
+
         elif tp == 'v': # VARIANT_BOOL type
             def _getvalue(self):
                 return bool(self._buffer[0])
diff --git a/lib_pypy/ctypes_support.py b/lib_pypy/ctypes_support.py
--- a/lib_pypy/ctypes_support.py
+++ b/lib_pypy/ctypes_support.py
@@ -12,6 +12,8 @@
 if sys.platform == 'win32':
     import _ffi
     standard_c_lib = ctypes.CDLL('msvcrt', handle=_ffi.get_libc())
+elif sys.platform == 'cygwin':
+    standard_c_lib = ctypes.CDLL(ctypes.util.find_library('cygwin'))
 else:
     standard_c_lib = ctypes.CDLL(ctypes.util.find_library('c'))
 
diff --git a/lib_pypy/disassembler.py b/lib_pypy/disassembler.py
--- a/lib_pypy/disassembler.py
+++ b/lib_pypy/disassembler.py
@@ -24,6 +24,11 @@
         self.lineno = lineno
         self.line_starts_here = False
 
+    def __str__(self):
+        if self.arg is None:
+            return "%s" % (self.__class__.__name__,)
+        return "%s (%s)" % (self.__class__.__name__, self.arg)
+
     def __repr__(self):
         if self.arg is None:
             return "<%s at %d>" % (self.__class__.__name__, self.pos)
diff --git a/pypy/annotation/annrpython.py b/pypy/annotation/annrpython.py
--- a/pypy/annotation/annrpython.py
+++ b/pypy/annotation/annrpython.py
@@ -133,44 +133,6 @@
         self.build_graph_types(graph, inputcells, complete_now=False)
         self.complete_helpers(policy)
         return graph
-    
-    def annotate_helper_method(self, _class, attr, args_s, policy=None):
-        """ Warning! this method is meant to be used between
-        annotation and rtyping
-        """
-        if policy is None:
-            from pypy.annotation.policy import AnnotatorPolicy
-            policy = AnnotatorPolicy()
-        
-        assert attr != '__class__'
-        classdef = self.bookkeeper.getuniqueclassdef(_class)
-        attrdef = classdef.find_attribute(attr)
-        s_result = attrdef.getvalue()
-        classdef.add_source_for_attribute(attr, classdef.classdesc)
-        self.bookkeeper
-        assert isinstance(s_result, annmodel.SomePBC)
-        olddesc = s_result.any_description()
-        desc = olddesc.bind_self(classdef)
-        args = self.bookkeeper.build_args("simple_call", args_s[:])
-        desc.consider_call_site(self.bookkeeper, desc.getcallfamily(), [desc],
-            args, annmodel.s_ImpossibleValue, None)
-        result = []
-        def schedule(graph, inputcells):
-            result.append((graph, inputcells))
-            return annmodel.s_ImpossibleValue
-
-        prevpolicy = self.policy
-        self.policy = policy
-        self.bookkeeper.enter(None)
-        try:
-            desc.pycall(schedule, args, annmodel.s_ImpossibleValue)
-        finally:
-            self.bookkeeper.leave()
-            self.policy = prevpolicy
-        [(graph, inputcells)] = result
-        self.build_graph_types(graph, inputcells, complete_now=False)
-        self.complete_helpers(policy)
-        return graph
 
     def complete_helpers(self, policy):
         saved = self.policy, self.added_blocks
diff --git a/pypy/annotation/binaryop.py b/pypy/annotation/binaryop.py
--- a/pypy/annotation/binaryop.py
+++ b/pypy/annotation/binaryop.py
@@ -659,7 +659,7 @@
 
     def mul((str1, int2)): # xxx do we want to support this
         getbookkeeper().count("str_mul", str1, int2)
-        return SomeString()
+        return SomeString(no_nul=str1.no_nul)
 
 class __extend__(pairtype(SomeUnicodeString, SomeInteger)):
     def getitem((str1, int2)):
diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py
--- a/pypy/annotation/bookkeeper.py
+++ b/pypy/annotation/bookkeeper.py
@@ -531,8 +531,11 @@
                 try:
                     assert pyobj._freeze_()
                 except AttributeError:
-                    raise Exception("unexpected prebuilt constant: %r" % (
-                        pyobj,))
+                    if hasattr(pyobj, '__call__'):
+                        msg = "object with a __call__ is not RPython"
+                    else:
+                        msg = "unexpected prebuilt constant"
+                    raise Exception("%s: %r" % (msg, pyobj))
                 result = self.getfrozen(pyobj)
             self.descs[pyobj] = result
             return result
diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -514,9 +514,9 @@
                     continue
                 self.add_source_attribute(name, value, mixin=True)
 
-    def add_sources_for_class(self, cls, mixin=False):
+    def add_sources_for_class(self, cls):
         for name, value in cls.__dict__.items():
-            self.add_source_attribute(name, value, mixin)
+            self.add_source_attribute(name, value)
 
     def getallclassdefs(self):
         return self._classdefs.values()
diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py
--- a/pypy/annotation/test/test_annrpython.py
+++ b/pypy/annotation/test/test_annrpython.py
@@ -2138,6 +2138,15 @@
         assert isinstance(s, annmodel.SomeString)
         assert s.no_nul
 
+    def test_mul_str0(self):
+        def f(s):
+            return s*10
+        a = self.RPythonAnnotator()
+        s = a.build_types(f, [annmodel.SomeString(no_nul=True)])
+        assert isinstance(s, annmodel.SomeString)
+        assert s.no_nul
+        
+
     def test_non_none_and_none_with_isinstance(self):
         class A(object):
             pass
@@ -2738,20 +2747,6 @@
         s = a.build_types(f, [])
         assert s.knowntype == int
 
-    def test_helper_method_annotator(self):
-        def fun():
-            return 21
-
-        class A(object):
-            def helper(self):
-                return 42
-
-        a = self.RPythonAnnotator()
-        a.build_types(fun, [])
-        a.annotate_helper_method(A, "helper", [])
-        assert a.bookkeeper.getdesc(A.helper).getuniquegraph()
-        assert a.bookkeeper.getdesc(A().helper).getuniquegraph()
-
     def test_chr_out_of_bounds(self):
         def g(n, max):
             if n < max:
@@ -3769,6 +3764,37 @@
         assert isinstance(s, annmodel.SomeString)
         assert not s.can_be_None
 
+    def test_no___call__(self):
+        class X(object):
+            def __call__(self):
+                xxx
+        x = X()
+        def f():
+            return x
+        a = self.RPythonAnnotator()
+        e = py.test.raises(Exception, a.build_types, f, [])
+        assert 'object with a __call__ is not RPython' in str(e.value)
+
+    def test_os_getcwd(self):
+        import os
+        def fn():
+            return os.getcwd()
+        a = self.RPythonAnnotator()
+        s = a.build_types(fn, [])
+        assert isinstance(s, annmodel.SomeString)
+        assert s.no_nul
+
+    def test_os_getenv(self):
+        import os
+        def fn():
+            return os.environ.get('PATH')
+        a = self.RPythonAnnotator()
+        s = a.build_types(fn, [])
+        assert isinstance(s, annmodel.SomeString)
+        assert s.no_nul
+
+
+
 def g(n):
     return [0,1,2,n]
 
diff --git a/pypy/bin/py.py b/pypy/bin/py.py
--- a/pypy/bin/py.py
+++ b/pypy/bin/py.py
@@ -89,12 +89,12 @@
     space.setitem(space.sys.w_dict, space.wrap('executable'),
                   space.wrap(argv[0]))
 
-    # call pypy_initial_path: the side-effect is that it sets sys.prefix and
+    # call pypy_find_stdlib: the side-effect is that it sets sys.prefix and
     # sys.exec_prefix
-    srcdir = os.path.dirname(os.path.dirname(pypy.__file__))
-    space.appexec([space.wrap(srcdir)], """(srcdir):
+    executable = argv[0]
+    space.appexec([space.wrap(executable)], """(executable):
         import sys
-        sys.pypy_initial_path(srcdir)
+        sys.pypy_find_stdlib(executable)
     """)
 
     # set warning control options (if any)
diff --git a/pypy/bin/rpython b/pypy/bin/rpython
old mode 100644
new mode 100755
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -79,6 +79,7 @@
 module_dependencies = {
     '_multiprocessing': [('objspace.usemodules.rctime', True),
                          ('objspace.usemodules.thread', True)],
+    'cpyext': [('objspace.usemodules.array', True)],
     }
 module_suggests = {
     # the reason you want _rawffi is for ctypes, which
diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst
--- a/pypy/doc/coding-guide.rst
+++ b/pypy/doc/coding-guide.rst
@@ -610,10 +610,6 @@
     >>>> cPickle.__file__
     '/home/hpk/pypy-dist/lib_pypy/cPickle..py'
 
-    >>>> import opcode
-    >>>> opcode.__file__
-    '/home/hpk/pypy-dist/lib-python/modified-2.7/opcode.py'
-
     >>>> import os
     >>>> os.__file__
     '/home/hpk/pypy-dist/lib-python/2.7/os.py'
@@ -639,13 +635,9 @@
 
     contains pure Python reimplementation of modules.
 
-*lib-python/modified-2.7/*
-
-    The files and tests that we have modified from the CPython library.
-
 *lib-python/2.7/*
 
-    The unmodified CPython library. **Never ever check anything in there**.
+    The modified CPython library.
 
 .. _`modify modules`:
 
@@ -658,16 +650,9 @@
 by default and CPython has a number of places where it relies
 on some classes being old-style.
 
-If you want to change a module or test contained in ``lib-python/2.7``
-then make sure that you copy the file to our ``lib-python/modified-2.7``
-directory first.  In mercurial commandline terms this reads::
-
-    $ hg cp lib-python/2.7/somemodule.py lib-python/modified-2.7/
-
-and subsequently you edit and commit
-``lib-python/modified-2.7/somemodule.py``.  This copying operation is
-important because it keeps the original CPython tree clean and makes it
-obvious what we had to change.
+We just maintain those changes in place,
+to see what is changed we have a branch called `vendot/stdlib`
+wich contains the unmodified cpython stdlib
 
 .. _`mixed module mechanism`:
 .. _`mixed modules`:
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -45,9 +45,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '1.8'
+version = '1.9'
 # The full version, including alpha/beta/rc tags.
-release = '1.8'
+release = '1.9'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
--- a/pypy/doc/cppyy.rst
+++ b/pypy/doc/cppyy.rst
@@ -5,8 +5,10 @@
 The cppyy module provides C++ bindings for PyPy by using the reflection
 information extracted from C++ header files by means of the
 `Reflex package`_.
-For this to work, you have to both install Reflex and build PyPy from the
-reflex-support branch.
+For this to work, you have to both install Reflex and build PyPy from source,
+as the cppyy module is not enabled by default.
+Note that the development version of cppyy lives in the reflex-support
+branch.
 As indicated by this being a branch, support for Reflex is still
 experimental.
 However, it is functional enough to put it in the hands of those who want
@@ -71,23 +73,33 @@
 .. _`recent snapshot`: http://cern.ch/wlav/reflex-2012-05-02.tar.bz2
 .. _`gccxml`: http://www.gccxml.org
 
-Next, get the `PyPy sources`_, select the reflex-support branch, and build
-pypy-c.
+Next, get the `PyPy sources`_, optionally select the reflex-support branch,
+and build it.
 For the build to succeed, the ``$ROOTSYS`` environment variable must point to
-the location of your ROOT (or standalone Reflex) installation::
+the location of your ROOT (or standalone Reflex) installation, or the
+``root-config`` utility must be accessible through ``PATH`` (e.g. by adding
+``$ROOTSYS/bin`` to ``PATH``).
+In case of the former, include files are expected under ``$ROOTSYS/include``
+and libraries under ``$ROOTSYS/lib``.
+Then run the translation to build ``pypy-c``::
 
     $ hg clone https://bitbucket.org/pypy/pypy
     $ cd pypy
-    $ hg up reflex-support
+    $ hg up reflex-support         # optional
     $ cd pypy/translator/goal
+    
+    # This example shows python, but using pypy-c is faster and uses less memory
     $ python translate.py -O jit --gcrootfinder=shadowstack targetpypystandalone.py --withmod-cppyy
 
 This will build a ``pypy-c`` that includes the cppyy module, and through that,
 Reflex support.
 Of course, if you already have a pre-built version of the ``pypy`` interpreter,
 you can use that for the translation rather than ``python``.
+If not, you may want `to obtain a binary distribution`_ to speed up the
+translation step.
 
 .. _`PyPy sources`: https://bitbucket.org/pypy/pypy/overview
+.. _`to obtain a binary distribution`: http://doc.pypy.org/en/latest/getting-started.html#download-a-pre-built-pypy
 
 
 Basic example
@@ -115,7 +127,7 @@
 code::
 
     $ genreflex MyClass.h
-    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o libMyClassDict.so
+    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o libMyClassDict.so -L$ROOTSYS/lib -lReflex
 
 Now you're ready to use the bindings.
 Since the bindings are designed to look pythonistic, it should be
@@ -139,6 +151,51 @@
 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.
+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++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o libMyClassDict.so -L$ROOTSYS/lib -lReflex
+
+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
@@ -171,7 +228,7 @@
         std::string m_name;
     };
 
-    Base1* BaseFactory(const std::string& name, int i, double d) {
+    Base2* BaseFactory(const std::string& name, int i, double d) {
         return new Derived(name, i, d);
     }
 
@@ -213,7 +270,7 @@
 Now the reflection info can be generated and compiled::
 
     $ genreflex MyAdvanced.h --selection=MyAdvanced.xml
-    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyAdvanced_rflx.cpp -o libAdvExDict.so
+    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyAdvanced_rflx.cpp -o libAdvExDict.so -L$ROOTSYS/lib -lReflex
 
 and subsequently be used from PyPy::
 
@@ -237,7 +294,7 @@
 
 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 ``Base1``, yet the
+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
@@ -319,6 +376,11 @@
   The C++ side will not see any overridden methods on the python side, as
   cross-inheritance is planned but not yet supported.
 
+* **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.
+
 * **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.
@@ -361,6 +423,11 @@
   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.
@@ -429,7 +496,9 @@
         int m_i;
     };
 
-    template class std::vector<MyClass>;
+    #ifdef __GCCXML__
+    template class std::vector<MyClass>;   // explicit instantiation
+    #endif
 
 If you know for certain that all symbols will be linked in from other sources,
 you can also declare the explicit template instantiation ``extern``.
@@ -440,8 +509,9 @@
 internal namespace, rather than in the iterator classes.
 One way to handle this, is to deal with this once in a macro, then reuse that
 macro for all ``vector`` classes.
-Thus, the header above needs this, instead of just the explicit instantiation
-of the ``vector<MyClass>``::
+Thus, the header above needs this (again protected with
+``#ifdef __GCCXML__``), instead of just the explicit instantiation of the
+``vector<MyClass>``::
 
     #define STLTYPES_EXPLICIT_INSTANTIATION_DECL(STLTYPE, TTYPE)                      \
     template class std::STLTYPE< TTYPE >;                                             \
@@ -462,11 +532,9 @@
     $ cat MyTemplate.xml
     <lcgdict>
         <class pattern="std::vector<*>" />
-        <class pattern="__gnu_cxx::__normal_iterator<*>" />
-        <class pattern="__gnu_cxx::new_allocator<*>" />
+        <class pattern="std::vector<*>::iterator" />
         <class pattern="std::_Vector_base<*>" />
         <class pattern="std::_Vector_base<*>::_Vector_impl" />
-        <class pattern="std::allocator<*>" />
         <function name="__gnu_cxx::operator=="/>
         <function name="__gnu_cxx::operator!="/>
 
@@ -475,8 +543,8 @@
 
 Run the normal ``genreflex`` and compilation steps::
 
-    $ genreflex MyTemplate.h --selection=MyTemplate.xm
-    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyTemplate_rflx.cpp -o libTemplateDict.so
+    $ genreflex MyTemplate.h --selection=MyTemplate.xml
+    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyTemplate_rflx.cpp -o libTemplateDict.so -L$ROOTSYS/lib -lReflex
 
 Note: this is a dirty corner that clearly could do with some automation,
 even if the macro already helps.
@@ -550,7 +618,9 @@
 There are a couple of minor differences between PyCintex and cppyy, most to do
 with naming.
 The one that you will run into directly, is that PyCintex uses a function
-called ``loadDictionary`` rather than ``load_reflection_info``.
+called ``loadDictionary`` rather than ``load_reflection_info`` (it has the
+same rootmap-based class loader functionality, though, making this point
+somewhat moot).
 The reason for this is that Reflex calls the shared libraries that contain
 reflection info "dictionaries."
 However, in python, the name `dictionary` already has a well-defined meaning,
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
@@ -85,13 +85,6 @@
 
     _winreg
 
-  Note that only some of these modules are built-in in a typical
-  CPython installation, and the rest is from non built-in extension
-  modules.  This means that e.g. ``import parser`` will, on CPython,
-  find a local file ``parser.py``, while ``import sys`` will not find a
-  local file ``sys.py``.  In PyPy the difference does not exist: all
-  these modules are built-in.
-
 * Supported by being rewritten in pure Python (possibly using ``ctypes``):
   see the `lib_pypy/`_ directory.  Examples of modules that we
   support this way: ``ctypes``, ``cPickle``, ``cmath``, ``dbm``, ``datetime``...
@@ -324,5 +317,10 @@
   type and vice versa. For builtin types, a dictionary will be returned that
   cannot be changed (but still looks and behaves like a normal dictionary).
 
+* the ``__len__`` or ``__length_hint__`` special methods are sometimes
+  called by CPython to get a length estimate to preallocate internal arrays.
+  So far, PyPy never calls ``__len__`` for this purpose, and never calls
+  ``__length_hint__`` at all.
+
 
 .. include:: _ref.txt
diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst
--- a/pypy/doc/extending.rst
+++ b/pypy/doc/extending.rst
@@ -23,7 +23,7 @@
 
 * Write them in RPython as mixedmodule_, using *rffi* as bindings.
 
-* Write them in C++ and bind them through Reflex_ (EXPERIMENTAL)
+* Write them in C++ and bind them through Reflex_
 
 .. _ctypes: #CTypes
 .. _\_ffi: #LibFFI
diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst
--- a/pypy/doc/getting-started-python.rst
+++ b/pypy/doc/getting-started-python.rst
@@ -50,10 +50,10 @@
      libz-dev libbz2-dev libncurses-dev libexpat1-dev \
      libssl-dev libgc-dev python-sphinx python-greenlet
 
-   On a Fedora box these are::
+   On a Fedora-16 box these are::
 
      [user at fedora-or-rh-box ~]$ sudo yum install \
-     gcc make python-devel libffi-devel pkg-config \
+     gcc make python-devel libffi-devel pkgconfig \
      zlib-devel bzip2-devel ncurses-devel expat-devel \
      openssl-devel gc-devel python-sphinx python-greenlet
 
@@ -103,10 +103,12 @@
 executable. The executable behaves mostly like a normal Python interpreter::
 
     $ ./pypy-c
-    Python 2.7.2 (0e28b379d8b3, Feb 09 2012, 19:41:03)
-    [PyPy 1.8.0 with GCC 4.4.3] on linux2
+    Python 2.7.2 (341e1e3821ff, Jun 07 2012, 15:40:31)
+    [PyPy 1.9.0 with GCC 4.4.3] on linux2
     Type "help", "copyright", "credits" or "license" for more information.
-    And now for something completely different: ``this sentence is false''
+    And now for something completely different: ``RPython magically makes you rich
+    and famous (says so on the tin)''
+
     >>>> 46 - 4
     42
     >>>> from test import pystone
@@ -220,7 +222,6 @@
    ./include/
    ./lib_pypy/
    ./lib-python/2.7
-   ./lib-python/modified-2.7
    ./site-packages/
 
 The hierarchy shown above is relative to a PREFIX directory.  PREFIX is
diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst
--- a/pypy/doc/getting-started.rst
+++ b/pypy/doc/getting-started.rst
@@ -53,10 +53,10 @@
 PyPy is ready to be executed as soon as you unpack the tarball or the zip
 file, with no need to install it in any specific location::
 
-    $ tar xf pypy-1.8-linux.tar.bz2
-    $ ./pypy-1.8/bin/pypy
-    Python 2.7.2 (0e28b379d8b3, Feb 09 2012, 19:41:03)
-    [PyPy 1.8.0 with GCC 4.4.3] on linux2
+    $ tar xf pypy-1.9-linux.tar.bz2
+    $ ./pypy-1.9/bin/pypy
+    Python 2.7.2 (341e1e3821ff, Jun 07 2012, 15:40:31)
+    [PyPy 1.9.0 with GCC 4.4.3] on linux2
     Type "help", "copyright", "credits" or "license" for more information.
     And now for something completely different: ``it seems to me that once you
     settle on an execution / object model and / or bytecode format, you've already
@@ -76,14 +76,14 @@
 
     $ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
 
-    $ ./pypy-1.8/bin/pypy distribute_setup.py
+    $ ./pypy-1.9/bin/pypy distribute_setup.py
 
-    $ ./pypy-1.8/bin/pypy get-pip.py
+    $ ./pypy-1.9/bin/pypy get-pip.py
 
-    $ ./pypy-1.8/bin/pip install pygments  # for example
+    $ ./pypy-1.9/bin/pip install pygments  # for example
 
-3rd party libraries will be installed in ``pypy-1.8/site-packages``, and
-the scripts in ``pypy-1.8/bin``.
+3rd party libraries will be installed in ``pypy-1.9/site-packages``, and
+the scripts in ``pypy-1.9/bin``.
 
 Installing using virtualenv
 ---------------------------
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
@@ -23,7 +23,9 @@
   some of the next updates may be done before or after branching; make
   sure things are ported back to the trunk and to the branch as
   necessary
-* update pypy/doc/contributor.txt (and possibly LICENSE)
+* update pypy/doc/contributor.rst (and possibly LICENSE)
+* rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst
+  and create a fresh whatsnew_head.rst after the release
 * update README
 * change the tracker to have a new release tag to file bugs against
 * go to pypy/tool/release and run:
diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst
--- a/pypy/doc/index.rst
+++ b/pypy/doc/index.rst
@@ -15,7 +15,7 @@
 
 * `FAQ`_: some frequently asked questions.
 
-* `Release 1.8`_: the latest official release
+* `Release 1.9`_: the latest official release
 
 * `PyPy Blog`_: news and status info about PyPy 
 
@@ -75,7 +75,7 @@
 .. _`Getting Started`: getting-started.html
 .. _`Papers`: extradoc.html
 .. _`Videos`: video-index.html
-.. _`Release 1.8`: http://pypy.org/download.html
+.. _`Release 1.9`: http://pypy.org/download.html
 .. _`speed.pypy.org`: http://speed.pypy.org
 .. _`RPython toolchain`: translation.html
 .. _`potential project ideas`: project-ideas.html
@@ -120,9 +120,9 @@
 Windows, on top of .NET, and on top of Java.
 To dig into PyPy it is recommended to try out the current
 Mercurial default branch, which is always working or mostly working,
-instead of the latest release, which is `1.8`__.
+instead of the latest release, which is `1.9`__.
 
-.. __: release-1.8.0.html
+.. __: release-1.9.0.html
 
 PyPy is mainly developed on Linux and Mac OS X.  Windows is supported,
 but platform-specific bugs tend to take longer before we notice and fix
diff --git a/pypy/doc/release-1.9.0.rst b/pypy/doc/release-1.9.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-1.9.0.rst
@@ -0,0 +1,111 @@
+====================
+PyPy 1.9 - Yard Wolf
+====================
+
+We're pleased to announce the 1.9 release of PyPy. This release brings mostly
+bugfixes, performance improvements, other small improvements and overall
+progress on the `numpypy`_ effort.
+It also brings an improved situation on Windows and OS X.
+
+You can download the PyPy 1.9 release here:
+
+    http://pypy.org/download.html 
+
+.. _`numpypy`: http://pypy.org/numpydonate.html
+
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 1.9 and cpython 2.7.2`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 64 or
+Windows 32.  Windows 64 work is still stalling, we would welcome a volunteer
+to handle that.
+
+.. _`pypy 1.9 and cpython 2.7.2`: http://speed.pypy.org
+
+
+Thanks to our donors
+====================
+
+But first of all, we would like to say thank you to all people who
+donated some money to one of our four calls:
+
+  * `NumPy in PyPy`_ (got so far $44502 out of $60000, 74%)
+
+  * `Py3k (Python 3)`_ (got so far $43563 out of $105000, 41%)
+
+  * `Software Transactional Memory`_ (got so far $21791 of $50400, 43%)
+
+  * as well as our general PyPy pot.
+
+Thank you all for proving that it is indeed possible for a small team of
+programmers to get funded like that, at least for some
+time.  We want to include this thank you in the present release
+announcement even though most of the work is not finished yet.  More
+precisely, neither Py3k nor STM are ready to make it in an official release
+yet: people interested in them need to grab and (attempt to) translate
+PyPy from the corresponding branches (respectively ``py3k`` and
+``stm-thread``).
+
+.. _`NumPy in PyPy`: http://pypy.org/numpydonate.html
+.. _`Py3k (Python 3)`: http://pypy.org/py3donate.html
+.. _`Software Transactional Memory`: http://pypy.org/tmdonate.html
+
+Highlights
+==========
+
+* This release still implements Python 2.7.2.
+
+* Many bugs were corrected for Windows 32 bit.  This includes new
+  functionality to test the validity of file descriptors; and
+  correct handling of the calling convensions for ctypes.  (Still not
+  much progress on Win64.) A lot of work on this has been done by Matti Picus
+  and Amaury Forgeot d'Arc.
+
+* Improvements in ``cpyext``, our emulator for CPython C extension modules.
+  For example PyOpenSSL should now work.  We thank various people for help.
+
+* Sets now have strategies just like dictionaries. This means for example
+  that a set containing only ints will be more compact (and faster).
+
+* A lot of progress on various aspects of ``numpypy``. See the `numpy-status`_
+  page for the automatic report.
+
+* It is now possible to create and manipulate C-like structures using the
+  PyPy-only ``_ffi`` module.  The advantage over using e.g. ``ctypes`` is that
+  ``_ffi`` is very JIT-friendly, and getting/setting of fields is translated
+  to few assembler instructions by the JIT. However, this is mostly intended
+  as a low-level backend to be used by more user-friendly FFI packages, and
+  the API might change in the future. Use it at your own risk.
+
+* The non-x86 backends for the JIT are progressing but are still not
+  merged (ARMv7 and PPC64).
+
+* JIT hooks for inspecting the created assembler code have been improved.
+  See `JIT hooks documentation`_ for details.
+
+* ``select.kqueue`` has been added (BSD).
+
+* Handling of keyword arguments has been drastically improved in the best-case
+  scenario: proxy functions which simply forwards ``*args`` and ``**kwargs``
+  to another function now performs much better with the JIT.
+
+* List comprehension has been improved.
+
+.. _`numpy-status`: http://buildbot.pypy.org/numpy-status/latest.html
+.. _`JIT hooks documentation`: http://doc.pypy.org/en/latest/jit-hooks.html
+
+JitViewer
+=========
+
+There will be a corresponding 1.9 release of JitViewer which is guaranteed
+to work with PyPy 1.9. See the `JitViewer docs`_ for details.
+
+.. _`JitViewer docs`: http://bitbucket.org/pypy/jitviewer
+
+Cheers,
+The PyPy Team
diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py
--- a/pypy/doc/test/test_whatsnew.py
+++ b/pypy/doc/test/test_whatsnew.py
@@ -16,6 +16,7 @@
             startrev = parseline(line)
         elif line.startswith('.. branch:'):
             branches.add(parseline(line))
+    branches.discard('default')
     return startrev, branches
 
 def get_merged_branches(path, startrev, endrev):
@@ -51,6 +52,10 @@
 .. branch: hello
 
 qqq www ttt
+
+.. branch: default
+
+"default" should be ignored and not put in the set of documented branches
 """
     startrev, branches = parse_doc(s)
     assert startrev == '12345'
diff --git a/pypy/doc/whatsnew-1.9.rst b/pypy/doc/whatsnew-1.9.rst
--- a/pypy/doc/whatsnew-1.9.rst
+++ b/pypy/doc/whatsnew-1.9.rst
@@ -5,8 +5,12 @@
 .. this is the revision just after the creation of the release-1.8.x branch
 .. startrev: a4261375b359
 
+.. branch: default
+* Working hash function for numpy types.
+
 .. branch: array_equal
 .. branch: better-jit-hooks-2
+Improved jit hooks
 .. branch: faster-heapcache
 .. branch: faster-str-decode-escape
 .. branch: float-bytes
@@ -16,9 +20,14 @@
 .. branch: jit-frame-counter
 Put more debug info into resops.
 .. branch: kill-geninterp
+Kill "geninterp", an old attempt to statically turn some fixed
+app-level code to interp-level.
 .. branch: kqueue
 Finished select.kqueue.
 .. branch: kwargsdict-strategy
+Special dictionary strategy for dealing with \*\*kwds. Now having a simple
+proxy ``def f(*args, **kwds): return x(*args, **kwds`` should not make
+any allocations at all.
 .. branch: matrixmath-dot
 numpypy can now handle matrix multiplication.
 .. branch: merge-2.7.2
@@ -29,13 +38,19 @@
 cpyext: Better support for PyEval_SaveThread and other PyTreadState_*
 functions.
 .. branch: numppy-flatitter
+flatitier for numpy
 .. branch: numpy-back-to-applevel
+reuse more of original numpy
 .. branch: numpy-concatenate
+concatenation support for numpy
 .. branch: numpy-indexing-by-arrays-bool
+indexing by bool arrays
 .. branch: numpy-record-dtypes
+record dtypes on numpy has been started
 .. branch: numpy-single-jitdriver
 .. branch: numpy-ufuncs2
 .. branch: numpy-ufuncs3
+various refactorings regarding numpy
 .. branch: numpypy-issue1137
 .. branch: numpypy-out
 The "out" argument was added to most of the numypypy functions.
@@ -43,8 +58,13 @@
 .. branch: numpypy-ufuncs
 .. branch: pytest
 .. branch: safe-getargs-freelist
+CPyext improvements. For example PyOpenSSL should now work
 .. branch: set-strategies
+Sets now have strategies just like dictionaries. This means a set
+containing only ints will be more compact (and faster)
 .. branch: speedup-list-comprehension
+The simplest case of list comprehension is preallocating the correct size
+of the list. This speeds up select benchmarks quite significantly.
 .. branch: stdlib-unification
 The directory "lib-python/modified-2.7" has been removed, and its
 content merged into "lib-python/2.7".
@@ -62,8 +82,13 @@
 Many bugs were corrected for windows 32 bit. New functionality was added to
 test validity of file descriptors, leading to the removal of the  global 
 _invalid_parameter_handler
+.. branch: win32-kill
+Add os.kill to windows even if translating python does not have os.kill
+.. branch: win_ffi
+Handle calling conventions for the _ffi and ctypes modules
 .. branch: win64-stage1
 .. branch: zlib-mem-pressure
+Memory "leaks" associated with zlib are fixed.
 
 .. branch: ffistruct
 The ``ffistruct`` branch adds a very low level way to express C structures
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/whatsnew-head.rst
@@ -0,0 +1,18 @@
+======================
+What's new in PyPy xxx
+======================
+
+.. this is the revision of the last merge from default to release-1.9.x
+.. startrev: 8d567513d04d
+
+.. branch: default
+.. branch: app_main-refactor
+.. branch: win-ordinal
+.. branch: reflex-support
+Provides cppyy module (disabled by default) for access to C++ through Reflex.
+See doc/cppyy.rst for full details and functionality.
+.. branch: nupypy-axis-arg-check
+Check that axis arg is valid in _numpypy
+
+.. "uninteresting" branches that we should just ignore for the whatsnew:
+.. branch: slightly-shorter-c
diff --git a/pypy/interpreter/astcompiler/test/test_astbuilder.py b/pypy/interpreter/astcompiler/test/test_astbuilder.py
--- a/pypy/interpreter/astcompiler/test/test_astbuilder.py
+++ b/pypy/interpreter/astcompiler/test/test_astbuilder.py
@@ -1105,6 +1105,17 @@
         assert isinstance(s, ast.Str)
         assert space.eq_w(s.s, space.wrap(sentence))
 
+    def test_string_bug(self):
+        space = self.space
+        source = '# -*- encoding: utf8 -*-\nstuff = "x \xc3\xa9 \\n"\n'
+        info = pyparse.CompileInfo("<test>", "exec")
+        tree = self.parser.parse_source(source, info)
+        assert info.encoding == "utf8"
+        s = ast_from_node(space, tree, info).body[0].value
+        assert isinstance(s, ast.Str)
+        expected = ['x', ' ', chr(0xc3), chr(0xa9), ' ', '\n']
+        assert space.eq_w(s.s, space.wrap(''.join(expected)))
+
     def test_number(self):
         def get_num(s):
             node = self.get_first_expr(s)
diff --git a/pypy/interpreter/buffer.py b/pypy/interpreter/buffer.py
--- a/pypy/interpreter/buffer.py
+++ b/pypy/interpreter/buffer.py
@@ -44,6 +44,9 @@
         # May be overridden.  No bounds checks.
         return ''.join([self.getitem(i) for i in range(start, stop, step)])
 
+    def get_raw_address(self):
+        raise ValueError("no raw buffer")
+
     # __________ app-level support __________
 
     def descr_len(self, space):
diff --git a/pypy/interpreter/pyparser/parsestring.py b/pypy/interpreter/pyparser/parsestring.py
--- a/pypy/interpreter/pyparser/parsestring.py
+++ b/pypy/interpreter/pyparser/parsestring.py
@@ -97,7 +97,8 @@
         return space.wrap(v)
 
     need_encoding = (encoding is not None and
-                     encoding != "utf-8" and encoding != "iso-8859-1")
+                     encoding != "utf-8" and encoding != "utf8" and
+                     encoding != "iso-8859-1")
     assert 0 <= ps <= q
     substr = s[ps : q]
     if rawmode or '\\' not in s[ps:]:
@@ -129,19 +130,18 @@
     builder = StringBuilder(len(s))
     ps = 0
     end = len(s)
-    while 1:
-        ps2 = ps
-        while ps < end and s[ps] != '\\':
+    while ps < end:
+        if s[ps] != '\\':
+            # note that the C code has a label here.
+            # the logic is the same.
             if recode_encoding and ord(s[ps]) & 0x80:
                 w, ps = decode_utf8(space, s, ps, end, recode_encoding)
+                # Append bytes to output buffer.
                 builder.append(w)
-                ps2 = ps
             else:
+                builder.append(s[ps])
                 ps += 1
-        if ps > ps2:
-            builder.append_slice(s, ps2, ps)
-        if ps == end:
-            break
+            continue
 
         ps += 1
         if ps == end:
diff --git a/pypy/interpreter/pyparser/test/test_parsestring.py b/pypy/interpreter/pyparser/test/test_parsestring.py
--- a/pypy/interpreter/pyparser/test/test_parsestring.py
+++ b/pypy/interpreter/pyparser/test/test_parsestring.py
@@ -84,3 +84,10 @@
         s = '"""' + '\\' + '\n"""'
         w_ret = parsestring.parsestr(space, None, s)
         assert space.str_w(w_ret) == ''
+
+    def test_bug1(self):
+        space = self.space
+        expected = ['x', ' ', chr(0xc3), chr(0xa9), ' ', '\n']
+        input = ["'", 'x', ' ', chr(0xc3), chr(0xa9), ' ', chr(92), 'n', "'"]
+        w_ret = parsestring.parsestr(space, 'utf8', ''.join(input))
+        assert space.str_w(w_ret) == ''.join(expected)
diff --git a/pypy/jit/backend/arm/test/test_ztranslation.py b/pypy/jit/backend/arm/test/test_ztranslation.py
--- a/pypy/jit/backend/arm/test/test_ztranslation.py
+++ b/pypy/jit/backend/arm/test/test_ztranslation.py
@@ -74,7 +74,7 @@
         #
         from pypy.rpython.lltypesystem import lltype, rffi
         from pypy.rlib.libffi import types, CDLL, ArgChain
-        from pypy.rlib.test.test_libffi import get_libm_name
+        from pypy.rlib.test.test_clibffi import get_libm_name
         libm_name = get_libm_name(sys.platform)
         jitdriver2 = JitDriver(greens=[], reds = ['i', 'func', 'res', 'x'])
         def libffi_stuff(i, j):
diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -577,7 +577,6 @@
     def __init__(self, gc_ll_descr):
         self.llop1 = gc_ll_descr.llop1
         self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR
-        self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR
         self.fielddescr_tid = gc_ll_descr.fielddescr_tid
         #
         GCClass = gc_ll_descr.GCClass
@@ -592,6 +591,11 @@
             self.jit_wb_card_page_shift = GCClass.JIT_WB_CARD_PAGE_SHIFT
             self.jit_wb_cards_set_byteofs, self.jit_wb_cards_set_singlebyte = (
                 self.extract_flag_byte(self.jit_wb_cards_set))
+            #
+            # the x86 backend uses the following "accidental" facts to
+            # avoid one instruction:
+            assert self.jit_wb_cards_set_byteofs == self.jit_wb_if_flag_byteofs
+            assert self.jit_wb_cards_set_singlebyte == -0x80
         else:
             self.jit_wb_cards_set = 0
 
@@ -615,7 +619,7 @@
         # returns a function with arguments [array, index, newvalue]
         llop1 = self.llop1
         funcptr = llop1.get_write_barrier_from_array_failing_case(
-            self.WB_ARRAY_FUNCPTR)
+            self.WB_FUNCPTR)
         funcaddr = llmemory.cast_ptr_to_adr(funcptr)
         return cpu.cast_adr_to_int(funcaddr)    # this may return 0
 
@@ -655,10 +659,11 @@
 
     def _check_valid_gc(self):
         # we need the hybrid or minimark GC for rgc._make_sure_does_not_move()
-        # to work
-        if self.gcdescr.config.translation.gc not in ('hybrid', 'minimark'):
+        # to work.  Additionally, 'hybrid' is missing some stuff like
+        # jit_remember_young_pointer() for now.
+        if self.gcdescr.config.translation.gc not in ('minimark',):
             raise NotImplementedError("--gc=%s not implemented with the JIT" %
-                                      (gcdescr.config.translation.gc,))
+                                      (self.gcdescr.config.translation.gc,))
 
     def _make_gcrootmap(self):
         # to find roots in the assembler, make a GcRootMap
@@ -699,9 +704,7 @@
 
     def _setup_write_barrier(self):
         self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType(
-            [llmemory.Address, llmemory.Address], lltype.Void))
-        self.WB_ARRAY_FUNCPTR = lltype.Ptr(lltype.FuncType(
-            [llmemory.Address, lltype.Signed, llmemory.Address], lltype.Void))
+            [llmemory.Address], lltype.Void))
         self.write_barrier_descr = WriteBarrierDescr(self)
 
     def _make_functions(self, really_not_translated):
@@ -861,8 +864,7 @@
             # the GC, and call it immediately
             llop1 = self.llop1
             funcptr = llop1.get_write_barrier_failing_case(self.WB_FUNCPTR)
-            funcptr(llmemory.cast_ptr_to_adr(gcref_struct),
-                    llmemory.cast_ptr_to_adr(gcref_newptr))
+            funcptr(llmemory.cast_ptr_to_adr(gcref_struct))
 
     def can_use_nursery_malloc(self, size):
         return size < self.max_size_of_young_obj
diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py
--- a/pypy/jit/backend/llsupport/test/test_gc.py
+++ b/pypy/jit/backend/llsupport/test/test_gc.py
@@ -276,8 +276,8 @@
                             repr(offset_to_length), p))
         return p
 
-    def _write_barrier_failing_case(self, adr_struct, adr_newptr):
-        self.record.append(('barrier', adr_struct, adr_newptr))
+    def _write_barrier_failing_case(self, adr_struct):
+        self.record.append(('barrier', adr_struct))
 
     def get_write_barrier_failing_case(self, FPTRTYPE):
         return llhelper(FPTRTYPE, self._write_barrier_failing_case)
@@ -296,7 +296,7 @@
 
 
 class TestFramework(object):
-    gc = 'hybrid'
+    gc = 'minimark'
 
     def setup_method(self, meth):
         class config_(object):
@@ -402,7 +402,7 @@
         #
         s_hdr.tid |= gc_ll_descr.GCClass.JIT_WB_IF_FLAG
         gc_ll_descr.do_write_barrier(s_gcref, r_gcref)
-        assert self.llop1.record == [('barrier', s_adr, r_adr)]
+        assert self.llop1.record == [('barrier', s_adr)]
 
     def test_gen_write_barrier(self):
         gc_ll_descr = self.gc_ll_descr
diff --git a/pypy/jit/backend/llsupport/test/test_rewrite.py b/pypy/jit/backend/llsupport/test/test_rewrite.py
--- a/pypy/jit/backend/llsupport/test/test_rewrite.py
+++ b/pypy/jit/backend/llsupport/test/test_rewrite.py
@@ -205,7 +205,7 @@
     def setup_method(self, meth):
         class config_(object):
             class translation(object):
-                gc = 'hybrid'
+                gc = 'minimark'
                 gcrootfinder = 'asmgcc'
                 gctransformer = 'framework'
                 gcremovetypeptr = False
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -1141,6 +1141,79 @@
     def test_virtual_ref_finish(self):
         pass   # VIRTUAL_REF_FINISH must not reach the backend nowadays
 
+    def test_arguments_to_execute_token(self):
+        # this test checks that execute_token() can be called with any
+        # variant of ints and floats as arguments
+        if self.cpu.supports_floats:
+            numkinds = 2
+        else:
+            numkinds = 1
+        seed = random.randrange(0, 10000)
+        print 'Seed is', seed    # or choose it by changing the previous line
+        r = random.Random()
+        r.seed(seed)
+        for nb_args in range(50):
+            print 'Passing %d arguments to execute_token...' % nb_args
+            #
+            inputargs = []
+            values = []
+            for k in range(nb_args):
+                kind = r.randrange(0, numkinds)
+                if kind == 0:
+                    inputargs.append(BoxInt())
+                    values.append(r.randrange(-100000, 100000))
+                else:
+                    inputargs.append(BoxFloat())
+                    values.append(longlong.getfloatstorage(r.random()))
+            #
+            looptoken = JitCellToken()
+            faildescr = BasicFailDescr(42)
+            operations = []
+            retboxes = []
+            retvalues = []
+            #
+            ks = range(nb_args)
+            random.shuffle(ks)
+            for k in ks:
+                if isinstance(inputargs[k], BoxInt):
+                    newbox = BoxInt()
+                    x = r.randrange(-100000, 100000)
+                    operations.append(
+                        ResOperation(rop.INT_ADD, [inputargs[k],
+                                                   ConstInt(x)], newbox)
+                        )
+                    y = values[k] + x
+                else:
+                    newbox = BoxFloat()
+                    x = r.random()
+                    operations.append(
+                        ResOperation(rop.FLOAT_ADD, [inputargs[k],
+                                                     constfloat(x)], newbox)
+                        )
+                    y = longlong.getrealfloat(values[k]) + x
+                    y = longlong.getfloatstorage(y)
+                kk = r.randrange(0, len(retboxes)+1)
+                retboxes.insert(kk, newbox)
+                retvalues.insert(kk, y)
+            #
+            operations.append(
+                ResOperation(rop.FINISH, retboxes, None, descr=faildescr)
+                )
+            print inputargs
+            for op in operations:
+                print op
+            self.cpu.compile_loop(inputargs, operations, looptoken)
+            #
+            fail = self.cpu.execute_token(looptoken, *values)
+            assert fail.identifier == 42
+            #
+            for k in range(len(retvalues)):
+                if isinstance(retboxes[k], BoxInt):
+                    got = self.cpu.get_latest_value_int(k)
+                else:
+                    got = self.cpu.get_latest_value_float(k)
+                assert got == retvalues[k]
+
     def test_jump(self):
         # this test generates small loops where the JUMP passes many
         # arguments of various types, shuffling them around.
@@ -1994,12 +2067,12 @@
         assert not excvalue
 
     def test_cond_call_gc_wb(self):
-        def func_void(a, b):
-            record.append((a, b))
+        def func_void(a):
+            record.append(a)
         record = []
         #
         S = lltype.GcStruct('S', ('tid', lltype.Signed))
-        FUNC = self.FuncType([lltype.Ptr(S), lltype.Ptr(S)], lltype.Void)
+        FUNC = self.FuncType([lltype.Ptr(S)], lltype.Void)
         func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
         funcbox = self.get_funcbox(self.cpu, func_ptr)
         class WriteBarrierDescr(AbstractDescr):
@@ -2025,26 +2098,25 @@
                                    [BoxPtr(sgcref), ConstPtr(tgcref)],
                                    'void', descr=WriteBarrierDescr())
             if cond:
-                assert record == [(s, t)]
+                assert record == [s]
             else:
                 assert record == []
 
     def test_cond_call_gc_wb_array(self):
-        def func_void(a, b, c):
-            record.append((a, b, c))
+        def func_void(a):
+            record.append(a)
         record = []
         #
         S = lltype.GcStruct('S', ('tid', lltype.Signed))
-        FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)],
-                             lltype.Void)
+        FUNC = self.FuncType([lltype.Ptr(S)], lltype.Void)
         func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
         funcbox = self.get_funcbox(self.cpu, func_ptr)
         class WriteBarrierDescr(AbstractDescr):
             jit_wb_if_flag = 4096
             jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10')
             jit_wb_if_flag_singlebyte = 0x10
-            jit_wb_cards_set = 0
-            def get_write_barrier_from_array_fn(self, cpu):
+            jit_wb_cards_set = 0       # <= without card marking
+            def get_write_barrier_fn(self, cpu):
                 return funcbox.getint()
         #
         for cond in [False, True]:
@@ -2061,13 +2133,15 @@
                        [BoxPtr(sgcref), ConstInt(123), BoxPtr(sgcref)],
                        'void', descr=WriteBarrierDescr())
             if cond:
-                assert record == [(s, 123, s)]
+                assert record == [s]
             else:
                 assert record == []
 
     def test_cond_call_gc_wb_array_card_marking_fast_path(self):
-        def func_void(a, b, c):
-            record.append((a, b, c))
+        def func_void(a):
+            record.append(a)
+            if cond == 1:      # the write barrier sets the flag
+                s.data.tid |= 32768
         record = []
         #
         S = lltype.Struct('S', ('tid', lltype.Signed))
@@ -2081,34 +2155,40 @@
                                      ('card6', lltype.Char),
                                      ('card7', lltype.Char),
                                      ('data',  S))
-        FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)],
-                             lltype.Void)
+        FUNC = self.FuncType([lltype.Ptr(S)], lltype.Void)
         func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
         funcbox = self.get_funcbox(self.cpu, func_ptr)
         class WriteBarrierDescr(AbstractDescr):
             jit_wb_if_flag = 4096
             jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10')
             jit_wb_if_flag_singlebyte = 0x10
-            jit_wb_cards_set = 8192
-            jit_wb_cards_set_byteofs = struct.pack("i", 8192).index('\x20')
-            jit_wb_cards_set_singlebyte = 0x20
+            jit_wb_cards_set = 32768
+            jit_wb_cards_set_byteofs = struct.pack("i", 32768).index('\x80')
+            jit_wb_cards_set_singlebyte = -0x80
             jit_wb_card_page_shift = 7
             def get_write_barrier_from_array_fn(self, cpu):
                 return funcbox.getint()
         #
-        for BoxIndexCls in [BoxInt, ConstInt]:
-            for cond in [False, True]:
+        for BoxIndexCls in [BoxInt, ConstInt]*3:
+            for cond in [-1, 0, 1, 2]:
+                # cond=-1:GCFLAG_TRACK_YOUNG_PTRS, GCFLAG_CARDS_SET are not set
+                # cond=0: GCFLAG_CARDS_SET is never set
+                # cond=1: GCFLAG_CARDS_SET is not set, but the wb sets it
+                # cond=2: GCFLAG_CARDS_SET is already set
                 print
                 print '_'*79
                 print 'BoxIndexCls =', BoxIndexCls
-                print 'JIT_WB_CARDS_SET =', cond
+                print 'testing cond =', cond
                 print
                 value = random.randrange(-sys.maxint, sys.maxint)
-                value |= 4096
-                if cond:
-                    value |= 8192
+                if cond >= 0:
+                    value |= 4096
                 else:
-                    value &= ~8192
+                    value &= ~4096
+                if cond == 2:
+                    value |= 32768
+                else:
+                    value &= ~32768
                 s = lltype.malloc(S_WITH_CARDS, immortal=True, zero=True)
                 s.data.tid = value
                 sgcref = rffi.cast(llmemory.GCREF, s.data)
@@ -2117,11 +2197,13 @@
                 self.execute_operation(rop.COND_CALL_GC_WB_ARRAY,
                            [BoxPtr(sgcref), box_index, BoxPtr(sgcref)],
                            'void', descr=WriteBarrierDescr())
-                if cond:
+                if cond in [0, 1]:
+                    assert record == [s.data]
+                else:
                     assert record == []
+                if cond in [1, 2]:
                     assert s.card6 == '\x02'
                 else:
-                    assert record == [(s.data, (9<<7) + 17, s.data)]
                     assert s.card6 == '\x00'
                 assert s.card0 == '\x00'
                 assert s.card1 == '\x00'
@@ -2130,6 +2212,9 @@
                 assert s.card4 == '\x00'
                 assert s.card5 == '\x00'
                 assert s.card7 == '\x00'
+                if cond == 1:
+                    value |= 32768
+                assert s.data.tid == value
 
     def test_force_operations_returning_void(self):
         values = []
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -10,7 +10,7 @@
 from pypy.rlib.jit import AsmInfo
 from pypy.jit.backend.model import CompiledLoopToken
 from pypy.jit.backend.x86.regalloc import (RegAlloc, get_ebp_ofs, _get_scale,
-    gpr_reg_mgr_cls, _valid_addressing_size)
+    gpr_reg_mgr_cls, xmm_reg_mgr_cls, _valid_addressing_size)
 
 from pypy.jit.backend.x86.arch import (FRAME_FIXED_SIZE, FORCE_INDEX_OFS, WORD,
                                        IS_X86_32, IS_X86_64)
@@ -83,6 +83,7 @@
         self.float_const_abs_addr = 0
         self.malloc_slowpath1 = 0
         self.malloc_slowpath2 = 0
+        self.wb_slowpath = [0, 0, 0, 0]
         self.memcpy_addr = 0
         self.setup_failure_recovery()
         self._debug = False
@@ -109,9 +110,13 @@
         self.memcpy_addr = self.cpu.cast_ptr_to_int(support.memcpy_fn)
         self._build_failure_recovery(False)
         self._build_failure_recovery(True)
+        self._build_wb_slowpath(False)
+        self._build_wb_slowpath(True)
         if self.cpu.supports_floats:
             self._build_failure_recovery(False, withfloats=True)
             self._build_failure_recovery(True, withfloats=True)
+            self._build_wb_slowpath(False, withfloats=True)
+            self._build_wb_slowpath(True, withfloats=True)
             support.ensure_sse2_floats()
             self._build_float_constants()
         self._build_propagate_exception_path()
@@ -344,6 +349,82 @@
         rawstart = mc.materialize(self.cpu.asmmemmgr, [])
         self.stack_check_slowpath = rawstart
 
+    def _build_wb_slowpath(self, withcards, withfloats=False):
+        descr = self.cpu.gc_ll_descr.write_barrier_descr
+        if descr is None:
+            return
+        if not withcards:
+            func = descr.get_write_barrier_fn(self.cpu)
+        else:
+            if descr.jit_wb_cards_set == 0:
+                return
+            func = descr.get_write_barrier_from_array_fn(self.cpu)
+            if func == 0:
+                return
+        #
+        # This builds a helper function called from the slow path of
+        # write barriers.  It must save all registers, and optionally
+        # all XMM registers.  It takes a single argument just pushed
+        # on the stack even on X86_64.  It must restore stack alignment
+        # accordingly.
+        mc = codebuf.MachineCodeBlockWrapper()
+        #
+        frame_size = (1 +     # my argument, considered part of my frame
+                      1 +     # my return address
+                      len(gpr_reg_mgr_cls.save_around_call_regs))
+        if withfloats:
+            frame_size += 16     # X86_32: 16 words for 8 registers;
+                                 # X86_64: just 16 registers
+        if IS_X86_32:
+            frame_size += 1      # argument to pass to the call
+        #
+        # align to a multiple of 16 bytes
+        frame_size = (frame_size + (CALL_ALIGN-1)) & ~(CALL_ALIGN-1)
+        #
+        correct_esp_by = (frame_size - 2) * WORD
+        mc.SUB_ri(esp.value, correct_esp_by)
+        #
+        ofs = correct_esp_by
+        if withfloats:
+            for reg in xmm_reg_mgr_cls.save_around_call_regs:
+                ofs -= 8
+                mc.MOVSD_sx(ofs, reg.value)
+        for reg in gpr_reg_mgr_cls.save_around_call_regs:
+            ofs -= WORD
+            mc.MOV_sr(ofs, reg.value)
+        #
+        if IS_X86_32:
+            mc.MOV_rs(eax.value, (frame_size - 1) * WORD)
+            mc.MOV_sr(0, eax.value)
+        elif IS_X86_64:
+            mc.MOV_rs(edi.value, (frame_size - 1) * WORD)
+        mc.CALL(imm(func))
+        #
+        if withcards:
+            # A final TEST8 before the RET, for the caller.  Careful to
+            # not follow this instruction with another one that changes
+            # the status of the CPU flags!
+            mc.MOV_rs(eax.value, (frame_size - 1) * WORD)
+            mc.TEST8(addr_add_const(eax, descr.jit_wb_if_flag_byteofs),
+                     imm(-0x80))
+        #
+        ofs = correct_esp_by
+        if withfloats:
+            for reg in xmm_reg_mgr_cls.save_around_call_regs:
+                ofs -= 8
+                mc.MOVSD_xs(reg.value, ofs)
+        for reg in gpr_reg_mgr_cls.save_around_call_regs:
+            ofs -= WORD
+            mc.MOV_rs(reg.value, ofs)
+        #
+        # ADD esp, correct_esp_by --- but cannot use ADD, because
+        # of its effects on the CPU flags
+        mc.LEA_rs(esp.value, correct_esp_by)
+        mc.RET16_i(WORD)
+        #
+        rawstart = mc.materialize(self.cpu.asmmemmgr, [])
+        self.wb_slowpath[withcards + 2 * withfloats] = rawstart
+
     @staticmethod
     @rgc.no_collect
     def _release_gil_asmgcc(css):
@@ -2324,102 +2405,83 @@
 
     def genop_discard_cond_call_gc_wb(self, op, arglocs):
         # Write code equivalent to write_barrier() in the GC: it checks
-        # a flag in the object at arglocs[0], and if set, it calls the
-        # function remember_young_pointer() from the GC.  The arguments
-        # to the call are in arglocs[:N].  The rest, arglocs[N:], contains
-        # registers that need to be saved and restored across the call.
-        # N is either 2 (regular write barrier) or 3 (array write barrier).
+        # a flag in the object at arglocs[0], and if set, it calls a
+        # helper piece of assembler.  The latter saves registers as needed
+        # and call the function jit_remember_young_pointer() from the GC.
         descr = op.getdescr()
         if we_are_translated():
             cls = self.cpu.gc_ll_descr.has_write_barrier_class()
             assert cls is not None and isinstance(descr, cls)
         #
         opnum = op.getopnum()
-        if opnum == rop.COND_CALL_GC_WB:
-            N = 2
-            func = descr.get_write_barrier_fn(self.cpu)
-            card_marking = False
-        elif opnum == rop.COND_CALL_GC_WB_ARRAY:
-            N = 3
-            func = descr.get_write_barrier_from_array_fn(self.cpu)
-            assert func != 0
-            card_marking = descr.jit_wb_cards_set != 0
-        else:
-            raise AssertionError(opnum)
+        card_marking = False
+        mask = descr.jit_wb_if_flag_singlebyte
+        if opnum == rop.COND_CALL_GC_WB_ARRAY and descr.jit_wb_cards_set != 0:
+            # assumptions the rest of the function depends on:
+            assert (descr.jit_wb_cards_set_byteofs ==
+                    descr.jit_wb_if_flag_byteofs)
+            assert descr.jit_wb_cards_set_singlebyte == -0x80
+            card_marking = True
+            mask = descr.jit_wb_if_flag_singlebyte | -0x80
         #
         loc_base = arglocs[0]
         self.mc.TEST8(addr_add_const(loc_base, descr.jit_wb_if_flag_byteofs),
-                      imm(descr.jit_wb_if_flag_singlebyte))
+                      imm(mask))
         self.mc.J_il8(rx86.Conditions['Z'], 0) # patched later
         jz_location = self.mc.get_relative_pos()
 
         # for cond_call_gc_wb_array, also add another fast path:
         # if GCFLAG_CARDS_SET, then we can just set one bit and be done
         if card_marking:
-            self.mc.TEST8(addr_add_const(loc_base,
-                                         descr.jit_wb_cards_set_byteofs),
-                          imm(descr.jit_wb_cards_set_singlebyte))
-            self.mc.J_il8(rx86.Conditions['NZ'], 0) # patched later
-            jnz_location = self.mc.get_relative_pos()
+            # GCFLAG_CARDS_SET is in this byte at 0x80, so this fact can
+            # been checked by the status flags of the previous TEST8
+            self.mc.J_il8(rx86.Conditions['S'], 0) # patched later
+            js_location = self.mc.get_relative_pos()
         else:
-            jnz_location = 0
+            js_location = 0
 
-        # the following is supposed to be the slow path, so whenever possible
-        # we choose the most compact encoding over the most efficient one.
-        if IS_X86_32:
-            limit = -1      # push all arglocs on the stack
-        elif IS_X86_64:
-            limit = N - 1   # push only arglocs[N:] on the stack
-        for i in range(len(arglocs)-1, limit, -1):
-            loc = arglocs[i]
-            if isinstance(loc, RegLoc):
-                self.mc.PUSH_r(loc.value)
-            else:
-                assert not IS_X86_64 # there should only be regs in arglocs[N:]
-                self.mc.PUSH_i32(loc.getint())
-        if IS_X86_64:
-            # We clobber these registers to pass the arguments, but that's
-            # okay, because consider_cond_call_gc_wb makes sure that any
-            # caller-save registers with values in them are present in
-            # arglocs[N:] too, so they are saved on the stack above and
-            # restored below.
-            if N == 2:
-                callargs = [edi, esi]
-            else:
-                callargs = [edi, esi, edx]
-            remap_frame_layout(self, arglocs[:N], callargs,
-                               X86_64_SCRATCH_REG)
+        # Write only a CALL to the helper prepared in advance, passing it as
+        # argument the address of the structure we are writing into
+        # (the first argument to COND_CALL_GC_WB).
+        helper_num = card_marking
+        if self._regalloc.xrm.reg_bindings:
+            helper_num += 2
+        if self.wb_slowpath[helper_num] == 0:    # tests only
+            assert not we_are_translated()
+            self.cpu.gc_ll_descr.write_barrier_descr = descr
+            self._build_wb_slowpath(card_marking,
+                                    bool(self._regalloc.xrm.reg_bindings))
+            assert self.wb_slowpath[helper_num] != 0
         #
-        # misaligned stack in the call, but it's ok because the write barrier
-        # is not going to call anything more.  Also, this assumes that the
-        # write barrier does not touch the xmm registers.  (Slightly delicate
-        # assumption, given that the write barrier can end up calling the
-        # platform's malloc() from AddressStack.append().  XXX may need to
-        # be done properly)
-        self.mc.CALL(imm(func))
-        if IS_X86_32:
-            self.mc.ADD_ri(esp.value, N*WORD)
-        for i in range(N, len(arglocs)):
-            loc = arglocs[i]
-            assert isinstance(loc, RegLoc)
-            self.mc.POP_r(loc.value)
+        self.mc.PUSH(loc_base)
+        self.mc.CALL(imm(self.wb_slowpath[helper_num]))
 
-        # if GCFLAG_CARDS_SET, then we can do the whole thing that would
-        # be done in the CALL above with just four instructions, so here
-        # is an inline copy of them
         if card_marking:
-            self.mc.JMP_l8(0) # jump to the exit, patched later
-            jmp_location = self.mc.get_relative_pos()
-            # patch the JNZ above
-            offset = self.mc.get_relative_pos() - jnz_location
+            # The helper ends again with a check of the flag in the object.
+            # So here, we can simply write again a 'JNS', which will be
+            # taken if GCFLAG_CARDS_SET is still not set.
+            self.mc.J_il8(rx86.Conditions['NS'], 0) # patched later
+            jns_location = self.mc.get_relative_pos()
+            #
+            # patch the JS above
+            offset = self.mc.get_relative_pos() - js_location
             assert 0 < offset <= 127
-            self.mc.overwrite(jnz_location-1, chr(offset))
+            self.mc.overwrite(js_location-1, chr(offset))
             #
+            # case GCFLAG_CARDS_SET: emit a few instructions to do
+            # directly the card flag setting
             loc_index = arglocs[1]
             if isinstance(loc_index, RegLoc):
-                # choose a scratch register
-                tmp1 = loc_index
-                self.mc.PUSH_r(tmp1.value)
+                if IS_X86_64 and isinstance(loc_base, RegLoc):
+                    # copy loc_index into r11
+                    tmp1 = X86_64_SCRATCH_REG
+                    self.mc.MOV_rr(tmp1.value, loc_index.value)
+                    final_pop = False
+                else:
+                    # must save the register loc_index before it is mutated
+                    self.mc.PUSH_r(loc_index.value)
+                    tmp1 = loc_index
+                    final_pop = True
                 # SHR tmp, card_page_shift
                 self.mc.SHR_ri(tmp1.value, descr.jit_wb_card_page_shift)
                 # XOR tmp, -8
@@ -2427,7 +2489,9 @@
                 # BTS [loc_base], tmp
                 self.mc.BTS(addr_add_const(loc_base, 0), tmp1)
                 # done
-                self.mc.POP_r(tmp1.value)
+                if final_pop:
+                    self.mc.POP_r(loc_index.value)
+                #
             elif isinstance(loc_index, ImmedLoc):
                 byte_index = loc_index.value >> descr.jit_wb_card_page_shift
                 byte_ofs = ~(byte_index >> 3)
@@ -2435,11 +2499,12 @@
                 self.mc.OR8(addr_add_const(loc_base, byte_ofs), imm(byte_val))
             else:
                 raise AssertionError("index is neither RegLoc nor ImmedLoc")
-            # patch the JMP above
-            offset = self.mc.get_relative_pos() - jmp_location
+            #
+            # patch the JNS above
+            offset = self.mc.get_relative_pos() - jns_location
             assert 0 < offset <= 127
-            self.mc.overwrite(jmp_location-1, chr(offset))
-        #
+            self.mc.overwrite(jns_location-1, chr(offset))
+
         # patch the JZ above
         offset = self.mc.get_relative_pos() - jz_location
         assert 0 < offset <= 127
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -922,16 +922,6 @@
         # or setarrayitem_gc. It avoids loading it twice from the memory.
         arglocs = [self.rm.make_sure_var_in_reg(op.getarg(i), args)
                    for i in range(N)]
-        # add eax, ecx and edx as extra "arguments" to ensure they are
-        # saved and restored.  Fish in self.rm to know which of these
-        # registers really need to be saved (a bit of a hack).  Moreover,
-        # we don't save and restore any SSE register because the called
-        # function, a GC write barrier, is known not to touch them.
-        # See remember_young_pointer() in rpython/memory/gc/generation.py.
-        for v, reg in self.rm.reg_bindings.items():
-            if (reg in self.rm.save_around_call_regs
-                and self.rm.stays_alive(v)):
-                arglocs.append(reg)
         self.PerformDiscard(op, arglocs)
         self.rm.possibly_free_vars_for_op(op)
 
diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py
--- a/pypy/jit/backend/x86/rx86.py
+++ b/pypy/jit/backend/x86/rx86.py
@@ -316,6 +316,13 @@
         assert rexbyte == 0
     return 0
 
+# REX prefixes: 'rex_w' generates a REX_W, forcing the instruction
+# to operate on 64-bit.  'rex_nw' doesn't, so the instruction operates
+# on 32-bit or less; the complete REX prefix is omitted if unnecessary.
+# 'rex_fw' is a special case which doesn't generate a REX_W but forces
+# the REX prefix in all cases.  It is only useful on instructions which
+# have an 8-bit register argument, to force access to the "sil" or "dil"
+# registers (as opposed to "ah-dh").
 rex_w  = encode_rex, 0, (0x40 | REX_W), None      # a REX.W prefix
 rex_nw = encode_rex, 0, 0, None                   # an optional REX prefix
 rex_fw = encode_rex, 0, 0x40, None                # a forced REX prefix
@@ -496,9 +503,9 @@
     AND8_rr = insn(rex_fw, '\x20', byte_register(1), byte_register(2,8), '\xC0')
 
     OR8_rr = insn(rex_fw, '\x08', byte_register(1), byte_register(2,8), '\xC0')
-    OR8_mi = insn(rex_fw, '\x80', orbyte(1<<3), mem_reg_plus_const(1),
+    OR8_mi = insn(rex_nw, '\x80', orbyte(1<<3), mem_reg_plus_const(1),
                   immediate(2, 'b'))
-    OR8_ji = insn(rex_fw, '\x80', orbyte(1<<3), abs_, immediate(1),
+    OR8_ji = insn(rex_nw, '\x80', orbyte(1<<3), abs_, immediate(1),
                   immediate(2, 'b'))
 
     NEG_r = insn(rex_w, '\xF7', register(1), '\xD8')
@@ -531,7 +538,13 @@
 
     PUSH_r = insn(rex_nw, register(1), '\x50')
     PUSH_b = insn(rex_nw, '\xFF', orbyte(6<<3), stack_bp(1))
+    PUSH_i8 = insn('\x6A', immediate(1, 'b'))
     PUSH_i32 = insn('\x68', immediate(1, 'i'))
+    def PUSH_i(mc, immed):
+        if single_byte(immed):
+            mc.PUSH_i8(immed)
+        else:
+            mc.PUSH_i32(immed)
 
     POP_r = insn(rex_nw, register(1), '\x58')
     POP_b = insn(rex_nw, '\x8F', orbyte(0<<3), stack_bp(1))
diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py
--- a/pypy/jit/backend/x86/test/test_rx86.py
+++ b/pypy/jit/backend/x86/test/test_rx86.py
@@ -183,7 +183,8 @@
 
 def test_push32():
     cb = CodeBuilder32
-    assert_encodes_as(cb, 'PUSH_i32', (9,), '\x68\x09\x00\x00\x00')
+    assert_encodes_as(cb, 'PUSH_i', (0x10009,), '\x68\x09\x00\x01\x00')
+    assert_encodes_as(cb, 'PUSH_i', (9,), '\x6A\x09')
 
 def test_sub_ji8():
     cb = CodeBuilder32
diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py
--- a/pypy/jit/backend/x86/test/test_ztranslation.py
+++ b/pypy/jit/backend/x86/test/test_ztranslation.py
@@ -69,7 +69,7 @@
         #
         from pypy.rpython.lltypesystem import lltype, rffi
         from pypy.rlib.libffi import types, CDLL, ArgChain
-        from pypy.rlib.test.test_libffi import get_libm_name
+        from pypy.rlib.test.test_clibffi import get_libm_name
         libm_name = get_libm_name(sys.platform)
         jitdriver2 = JitDriver(greens=[], reds = ['i', 'func', 'res', 'x'])
         def libffi_stuff(i, j):
diff --git a/pypy/jit/backend/x86/tool/viewcode.py b/pypy/jit/backend/x86/tool/viewcode.py
--- a/pypy/jit/backend/x86/tool/viewcode.py
+++ b/pypy/jit/backend/x86/tool/viewcode.py
@@ -253,7 +253,7 @@
                 self.logentries[addr] = pieces[3]
             elif line.startswith('SYS_EXECUTABLE '):
                 filename = line[len('SYS_EXECUTABLE '):].strip()
-                if filename != self.executable_name:
+                if filename != self.executable_name and filename != '??':
                     self.symbols.update(load_symbols(filename))
                     self.executable_name = filename
 
diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py
--- a/pypy/jit/codewriter/policy.py
+++ b/pypy/jit/codewriter/policy.py
@@ -48,8 +48,6 @@
         mod = func.__module__ or '?'
         if mod.startswith('pypy.rpython.module.'):
             return True
-        if mod == 'pypy.translator.goal.nanos':    # more helpers
-            return True
         return False
 
     def look_inside_graph(self, graph):
diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py
--- a/pypy/jit/metainterp/optimizeopt/fficall.py
+++ b/pypy/jit/metainterp/optimizeopt/fficall.py
@@ -133,7 +133,7 @@
     optimize_CALL_MAY_FORCE = optimize_CALL
 
     def optimize_FORCE_TOKEN(self, op):
-        # The handling of force_token needs a bit of exaplanation.
+        # The handling of force_token needs a bit of explanation.
         # The original trace which is getting optimized looks like this:
         #    i1 = force_token()
         #    setfield_gc(p0, i1, ...)
diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py
--- a/pypy/jit/tl/pypyjit.py
+++ b/pypy/jit/tl/pypyjit.py
@@ -43,6 +43,7 @@
 config.objspace.usemodules._lsprof = False
 #
 config.objspace.usemodules._ffi = True
+#config.objspace.usemodules.cppyy = True
 config.objspace.usemodules.micronumpy = False
 #
 set_pypy_opt_level(config, level='jit')
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -3,7 +3,6 @@
 from pypy.interpreter.mixedmodule import MixedModule
 from pypy.module.imp.importing import get_pyc_magic
 
-
 class BuildersModule(MixedModule):
     appleveldefs = {}
 
@@ -43,7 +42,10 @@
         'lookup_special'            : 'interp_magic.lookup_special',
         'do_what_I_mean'            : 'interp_magic.do_what_I_mean',
         'list_strategy'             : 'interp_magic.list_strategy',
+        'validate_fd'               : 'interp_magic.validate_fd',
     }
+    if sys.platform == 'win32':
+        interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp'
 
     submodules = {
         "builders": BuildersModule,
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -1,9 +1,10 @@
 from pypy.interpreter.baseobjspace import ObjSpace, W_Root
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import OperationError, wrap_oserror
 from pypy.interpreter.gateway import unwrap_spec
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.objspace.std.typeobject import MethodCache
 from pypy.objspace.std.mapdict import IndexCache
+from pypy.rlib import rposix
 
 def internal_repr(space, w_object):
     return space.wrap('%r' % (w_object,))
@@ -80,3 +81,17 @@
     else:
         w_msg = space.wrap("Can only get the list strategy of a list")
         raise OperationError(space.w_TypeError, w_msg)
+
+ at unwrap_spec(fd='c_int')
+def validate_fd(space, fd):
+    try:
+        rposix.validate_fd(fd)
+    except OSError, e:
+        raise wrap_oserror(space, e)
+
+def get_console_cp(space):
+    from pypy.rlib import rwin32    # Windows only
+    return space.newtuple([
+        space.wrap('cp%d' % rwin32.GetConsoleCP()),
+        space.wrap('cp%d' % rwin32.GetConsoleOutputCP()),
+        ])
diff --git a/pypy/module/_ffi/__init__.py b/pypy/module/_ffi/__init__.py
--- a/pypy/module/_ffi/__init__.py
+++ b/pypy/module/_ffi/__init__.py
@@ -1,4 +1,5 @@
 from pypy.interpreter.mixedmodule import MixedModule
+import os
 
 class Module(MixedModule):
 
@@ -10,7 +11,8 @@
         '_StructDescr': 'interp_struct.W__StructDescr',
         'Field':     'interp_struct.W_Field',
     }
-
+    if os.name == 'nt':
+        interpleveldefs['WinDLL'] = 'interp_funcptr.W_WinDLL'
     appleveldefs = {
         'Structure': 'app_struct.Structure',
         }
diff --git a/pypy/module/_ffi/interp_funcptr.py b/pypy/module/_ffi/interp_funcptr.py
--- a/pypy/module/_ffi/interp_funcptr.py
+++ b/pypy/module/_ffi/interp_funcptr.py
@@ -9,11 +9,57 @@
 #
 from pypy.rlib import jit
 from pypy.rlib import libffi
+from pypy.rlib.clibffi import get_libc_name, StackCheckError
 from pypy.rlib.rdynload import DLOpenError
 from pypy.rlib.rarithmetic import intmask, r_uint
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.module._ffi.type_converter import FromAppLevelConverter, ToAppLevelConverter
 
+import os
+if os.name == 'nt':
+    def _getfunc(space, CDLL, w_name, w_argtypes, w_restype):
+        argtypes_w, argtypes, w_restype, restype = unpack_argtypes(
+            space, w_argtypes, w_restype)
+        if space.isinstance_w(w_name, space.w_str):
+            name = space.str_w(w_name)
+            try:
+                func = CDLL.cdll.getpointer(name, argtypes, restype, 
+                                            flags = CDLL.flags)
+            except KeyError:
+                raise operationerrfmt(
+                    space.w_AttributeError,
+                    "No symbol %s found in library %s", name, CDLL.name)
+
+            return W_FuncPtr(func, argtypes_w, w_restype)
+        elif space.isinstance_w(w_name, space.w_int):
+            ordinal = space.int_w(w_name)
+            try:
+                func = CDLL.cdll.getpointer_by_ordinal(
+                    ordinal, argtypes, restype, 
+                    flags = CDLL.flags)
+            except KeyError:
+                raise operationerrfmt(
+                    space.w_AttributeError,
+                    "No ordinal %d found in library %s", ordinal, CDLL.name)
+            return W_FuncPtr(func, argtypes_w, w_restype)
+        else:
+            raise OperationError(space.w_TypeError, space.wrap(
+                    'function name must be a string or integer'))
+else:    
+    @unwrap_spec(name=str)
+    def _getfunc(space, CDLL, w_name, w_argtypes, w_restype):
+        name = space.str_w(w_name)
+        argtypes_w, argtypes, w_restype, restype = unpack_argtypes(
+            space, w_argtypes, w_restype)
+        try:
+            func = CDLL.cdll.getpointer(name, argtypes, restype, 
+                                        flags = CDLL.flags)
+        except KeyError:
+            raise operationerrfmt(
+                space.w_AttributeError,
+                "No symbol %s found in library %s", name, CDLL.name)
+
+        return W_FuncPtr(func, argtypes_w, w_restype)
 
 def unwrap_ffitype(space, w_argtype, allow_void=False):
     res = w_argtype.get_ffitype()
@@ -59,7 +105,10 @@
         self = jit.promote(self)
         argchain = self.build_argchain(space, args_w)
         func_caller = CallFunctionConverter(space, self.func, argchain)
-        return func_caller.do_and_wrap(self.w_restype)
+        try:
+            return func_caller.do_and_wrap(self.w_restype)
+        except StackCheckError, e:
+            raise OperationError(space.w_ValueError, space.wrap(e.message))
         #return self._do_call(space, argchain)
 
     def free_temp_buffers(self, space):
@@ -230,13 +279,14 @@
     restype = unwrap_ffitype(space, w_restype, allow_void=True)
     return argtypes_w, argtypes, w_restype, restype
 
- at unwrap_spec(addr=r_uint, name=str)
-def descr_fromaddr(space, w_cls, addr, name, w_argtypes, w_restype):
+ at unwrap_spec(addr=r_uint, name=str, flags=int)
+def descr_fromaddr(space, w_cls, addr, name, w_argtypes, 
+                    w_restype, flags=libffi.FUNCFLAG_CDECL):
     argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space,
                                                                w_argtypes,
                                                                w_restype)
     addr = rffi.cast(rffi.VOIDP, addr)
-    func = libffi.Func(name, argtypes, restype, addr)
+    func = libffi.Func(name, argtypes, restype, addr, flags)
     return W_FuncPtr(func, argtypes_w, w_restype)
 
 
@@ -254,6 +304,7 @@
 
 class W_CDLL(Wrappable):
     def __init__(self, space, name, mode):
+        self.flags = libffi.FUNCFLAG_CDECL
         self.space = space
         if name is None:
             self.name = "<None>"
@@ -265,18 +316,8 @@
             raise operationerrfmt(space.w_OSError, '%s: %s', self.name,
                                   e.msg or 'unspecified error')
 
-    @unwrap_spec(name=str)
-    def getfunc(self, space, name, w_argtypes, w_restype):
-        argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space,
-                                                                   w_argtypes,
-                                                                   w_restype)
-        try:
-            func = self.cdll.getpointer(name, argtypes, restype)
-        except KeyError:
-            raise operationerrfmt(space.w_AttributeError,
-                                  "No symbol %s found in library %s", name, self.name)
-
-        return W_FuncPtr(func, argtypes_w, w_restype)
+    def getfunc(self, space, w_name, w_argtypes, w_restype):
+        return _getfunc(space, self, w_name, w_argtypes, w_restype)
 
     @unwrap_spec(name=str)
     def getaddressindll(self, space, name):
@@ -284,8 +325,9 @@
             address_as_uint = rffi.cast(lltype.Unsigned,
                                         self.cdll.getaddressindll(name))
         except KeyError:
-            raise operationerrfmt(space.w_ValueError,
-                                  "No symbol %s found in library %s", name, self.name)
+            raise operationerrfmt(
+                space.w_ValueError,
+                "No symbol %s found in library %s", name, self.name)
         return space.wrap(address_as_uint)
 
 @unwrap_spec(name='str_or_None', mode=int)
@@ -300,10 +342,26 @@
     getaddressindll = interp2app(W_CDLL.getaddressindll),
     )
 
+class W_WinDLL(W_CDLL):
+    def __init__(self, space, name, mode):
+        W_CDLL.__init__(self, space, name, mode)
+        self.flags = libffi.FUNCFLAG_STDCALL
+
+ at unwrap_spec(name='str_or_None', mode=int)
+def descr_new_windll(space, w_type, name, mode=-1):
+    return space.wrap(W_WinDLL(space, name, mode))
+
+
+W_WinDLL.typedef = TypeDef(
+    '_ffi.WinDLL',
+    __new__     = interp2app(descr_new_windll),
+    getfunc     = interp2app(W_WinDLL.getfunc),
+    getaddressindll = interp2app(W_WinDLL.getaddressindll),
+    )
+
 # ========================================================================
 
 def get_libc(space):
-    from pypy.rlib.clibffi import get_libc_name
     try:
         return space.wrap(W_CDLL(space, get_libc_name(), -1))
     except OSError, e:
diff --git a/pypy/module/_ffi/interp_struct.py b/pypy/module/_ffi/interp_struct.py
--- a/pypy/module/_ffi/interp_struct.py
+++ b/pypy/module/_ffi/interp_struct.py
@@ -56,8 +56,7 @@
 
 class W__StructDescr(Wrappable):
 
-    def __init__(self, space, name):
-        self.space = space
+    def __init__(self, name):
         self.w_ffitype = W_FFIType('struct %s' % name, clibffi.FFI_TYPE_NULL,
                                    w_structdescr=self)
         self.fields_w = None
@@ -69,7 +68,6 @@
             raise operationerrfmt(space.w_ValueError,
                                   "%s's fields has already been defined",
                                   self.w_ffitype.name)
-        space = self.space
         fields_w = space.fixedview(w_fields)
         # note that the fields_w returned by compute_size_and_alignement has a
         # different annotation than the original: list(W_Root) vs list(W_Field)
@@ -104,11 +102,11 @@
         return W__StructInstance(self, allocate=False, autofree=True, rawmem=rawmem)
 
     @jit.elidable_promote('0')
-    def get_type_and_offset_for_field(self, name):
+    def get_type_and_offset_for_field(self, space, name):
         try:
             w_field = self.name2w_field[name]
         except KeyError:
-            raise operationerrfmt(self.space.w_AttributeError, '%s', name)
+            raise operationerrfmt(space.w_AttributeError, '%s', name)
 
         return w_field.w_ffitype, w_field.offset
 
@@ -116,7 +114,7 @@
 
 @unwrap_spec(name=str)
 def descr_new_structdescr(space, w_type, name, w_fields=None):
-    descr = W__StructDescr(space, name)
+    descr = W__StructDescr(name)
     if w_fields is not space.w_None:
         descr.define_fields(space, w_fields)
     return descr
@@ -185,13 +183,15 @@
 
     @unwrap_spec(name=str)
     def getfield(self, space, name):
-        w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(name)
+        w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(
+            space, name)
         field_getter = GetFieldConverter(space, self.rawmem, offset)
         return field_getter.do_and_wrap(w_ffitype)
 
     @unwrap_spec(name=str)
     def setfield(self, space, name, w_value):
-        w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(name)
+        w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(
+            space, name)
         field_setter = SetFieldConverter(space, self.rawmem, offset)
         field_setter.unwrap_and_do(w_ffitype, w_value)
 
diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py
--- a/pypy/module/_ffi/test/test_funcptr.py
+++ b/pypy/module/_ffi/test/test_funcptr.py
@@ -1,11 +1,11 @@
 from pypy.conftest import gettestobjspace
-from pypy.translator.platform import platform
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.module._rawffi.interp_rawffi import TYPEMAP
-from pypy.module._rawffi.tracker import Tracker
-from pypy.translator.platform import platform
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib.clibffi import get_libc_name
+from pypy.rlib.libffi import types
+from pypy.rlib.libffi import CDLL
+from pypy.rlib.test.test_clibffi import get_libm_name
 
-import os, sys, py
+import sys, py
 
 class BaseAppTestFFI(object):
 
@@ -37,9 +37,6 @@
         return str(platform.compile([c_file], eci, 'x', standalone=False))
 
     def setup_class(cls):
-        from pypy.rpython.lltypesystem import rffi
-        from pypy.rlib.libffi import get_libc_name, CDLL, types
-        from pypy.rlib.test.test_libffi import get_libm_name
         space = gettestobjspace(usemodules=('_ffi', '_rawffi'))
         cls.space = space
         cls.w_iswin32 = space.wrap(sys.platform == 'win32')
@@ -96,7 +93,7 @@
 
     def test_getaddressindll(self):
         import sys
-        from _ffi import CDLL, types
+        from _ffi import CDLL
         libm = CDLL(self.libm_name)
         pow_addr = libm.getaddressindll('pow')
         fff = sys.maxint*2-1
@@ -105,7 +102,6 @@
         assert pow_addr == self.pow_addr & fff
 
     def test_func_fromaddr(self):
-        import sys
         from _ffi import CDLL, types, FuncPtr
         libm = CDLL(self.libm_name)
         pow_addr = libm.getaddressindll('pow')
@@ -338,6 +334,22 @@
         assert sum_xy(100, 40) == 140
         assert sum_xy(200, 60) == 260 % 256
 
+    def test_unsigned_int_args(self):
+        r"""
+            DLLEXPORT unsigned int sum_xy_ui(unsigned int x, unsigned int y)
+            {
+                return x+y;
+            }
+        """
+        import sys
+        from _ffi import CDLL, types
+        maxint32 = 2147483647
+        libfoo = CDLL(self.libfoo_name)
+        sum_xy = libfoo.getfunc('sum_xy_ui', [types.uint, types.uint],
+                                types.uint)
+        assert sum_xy(maxint32, 1) == maxint32+1
+        assert sum_xy(maxint32, maxint32+2) == 0
+
     def test_signed_byte_args(self):
         """
             DLLEXPORT signed char sum_xy_sb(signed char x, signed char y)
@@ -553,3 +565,79 @@
             skip("unix specific")
         libnone = CDLL(None)
         raises(AttributeError, "libnone.getfunc('I_do_not_exist', [], types.void)")
+
+    def test_calling_convention1(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import WinDLL, types
+        libm = WinDLL(self.libm_name)
+        pow = libm.getfunc('pow', [types.double, types.double], types.double)
+        try:
+            pow(2, 3)
+        except ValueError, e:
+            assert e.message.startswith('Procedure called with')
+        else:
+            assert 0, 'test must assert, wrong calling convention'
+
+    def test_calling_convention2(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import WinDLL, types
+        kernel = WinDLL('Kernel32.dll')
+        sleep = kernel.getfunc('Sleep', [types.uint], types.void)
+        sleep(10)
+
+    def test_calling_convention3(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import CDLL, types
+        wrong_kernel = CDLL('Kernel32.dll')
+        wrong_sleep = wrong_kernel.getfunc('Sleep', [types.uint], types.void)
+        try:
+            wrong_sleep(10)
+        except ValueError, e:
+            assert e.message.startswith('Procedure called with')
+        else:
+            assert 0, 'test must assert, wrong calling convention'
+
+    def test_func_fromaddr2(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import CDLL, types, FuncPtr
+        from _rawffi import FUNCFLAG_STDCALL
+        libm = CDLL(self.libm_name)
+        pow_addr = libm.getaddressindll('pow')
+        wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow', 
+                [types.double, types.double], types.double, FUNCFLAG_STDCALL)
+        try:
+            wrong_pow(2, 3) == 8
+        except ValueError, e:
+            assert e.message.startswith('Procedure called with')
+        else:
+            assert 0, 'test must assert, wrong calling convention'
+
+    def test_func_fromaddr3(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import WinDLL, types, FuncPtr
+        from _rawffi import FUNCFLAG_STDCALL
+        kernel = WinDLL('Kernel32.dll')
+        sleep_addr = kernel.getaddressindll('Sleep')
+        sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint], 
+                            types.void, FUNCFLAG_STDCALL)
+        sleep(10)
+
+    def test_by_ordinal(self):
+        """
+            int DLLEXPORT AAA_first_ordinal_function()
+            {
+                return 42;
+            }
+        """
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import CDLL, types
+        libfoo = CDLL(self.libfoo_name)
+        f_name = libfoo.getfunc('AAA_first_ordinal_function', [], types.sint)
+        f_ordinal = libfoo.getfunc(1, [], types.sint)
+        assert f_name.getaddr() == f_ordinal.getaddr()
diff --git a/pypy/module/_ffi/test/test_struct.py b/pypy/module/_ffi/test/test_struct.py
--- a/pypy/module/_ffi/test/test_struct.py
+++ b/pypy/module/_ffi/test/test_struct.py
@@ -1,5 +1,5 @@
 import sys
-from pypy.conftest import gettestobjspace
+from pypy.conftest import gettestobjspace, option
 from pypy.module._ffi.test.test_funcptr import BaseAppTestFFI
 from pypy.module._ffi.interp_struct import compute_size_and_alignement, W_Field
 from pypy.module._ffi.interp_ffitype import app_types, W_FFIType
@@ -62,6 +62,7 @@
         dummy_type.c_alignment = rffi.cast(rffi.USHORT, 0)
         dummy_type.c_type = rffi.cast(rffi.USHORT, 0)
         cls.w_dummy_type = W_FFIType('dummy', dummy_type)
+        cls.w_runappdirect = cls.space.wrap(option.runappdirect)
         
     def test__StructDescr(self):
         from _ffi import _StructDescr, Field, types
@@ -99,6 +100,8 @@
         raises(AttributeError, "struct.setfield('missing', 42)")
 
     def test_unknown_type(self):
+        if self.runappdirect:
+            skip('cannot use self.dummy_type with -A')
         from _ffi import _StructDescr, Field
         fields = [
             Field('x', self.dummy_type),
diff --git a/pypy/module/_ffi/test/test_type_converter.py b/pypy/module/_ffi/test/test_type_converter.py
--- a/pypy/module/_ffi/test/test_type_converter.py
+++ b/pypy/module/_ffi/test/test_type_converter.py
@@ -126,3 +126,46 @@
         # then, try to pass explicit pointers
         self.check(app_types.char_p, self.space.wrap(42), 42)
         self.check(app_types.unichar_p, self.space.wrap(42), 42)        
+
+
+
+class DummyToAppLevelConverter(ToAppLevelConverter):
+
+    def get_all(self, w_ffitype):
+        return self.val
+
+    get_signed = get_all
+    get_unsigned = get_all
+    get_pointer = get_all
+    get_char = get_all        
+    get_unichar = get_all
+    get_longlong = get_all
+    get_char_p = get_all
+    get_unichar_p = get_all
+    get_float = get_all
+    get_singlefloat = get_all
+    get_unsigned_which_fits_into_a_signed = get_all
+    
+    def convert(self, w_ffitype, val):
+        self.val = val
+        return self.do_and_wrap(w_ffitype)
+
+
+class TestFromAppLevel(object):
+
+    def setup_class(cls):
+        cls.space = gettestobjspace(usemodules=('_ffi',))
+        converter = DummyToAppLevelConverter(cls.space)
+        cls.from_app_level = staticmethod(converter.convert)
+
+    def check(self, w_ffitype, val, w_expected):
+        w_v = self.from_app_level(w_ffitype, val)
+        assert self.space.eq_w(w_v, w_expected)
+
+    def test_int(self):
+        self.check(app_types.sint, 42, self.space.wrap(42))
+        self.check(app_types.sint, -sys.maxint-1, self.space.wrap(-sys.maxint-1))
+
+    def test_uint(self):
+        self.check(app_types.uint, 42, self.space.wrap(42))
+        self.check(app_types.uint, r_uint(sys.maxint+1), self.space.wrap(sys.maxint+1))
diff --git a/pypy/module/_ffi/test/test_ztranslation.py b/pypy/module/_ffi/test/test_ztranslation.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/test/test_ztranslation.py
@@ -0,0 +1,4 @@
+from pypy.objspace.fake.checkmodule import checkmodule
+
+def test__ffi_translates():
+    checkmodule('_ffi', '_rawffi')
diff --git a/pypy/module/_ffi/type_converter.py b/pypy/module/_ffi/type_converter.py
--- a/pypy/module/_ffi/type_converter.py
+++ b/pypy/module/_ffi/type_converter.py
@@ -205,7 +205,9 @@
         elif w_ffitype.is_signed():
             intval = self.get_signed(w_ffitype)
             return space.wrap(intval)
-        elif w_ffitype is app_types.ulong or w_ffitype is app_types.ulonglong:
+        elif (w_ffitype is app_types.ulonglong or
+              w_ffitype is app_types.ulong or (libffi.IS_32_BIT and
+                                               w_ffitype is app_types.uint)):
             # Note that we the second check (for ulonglong) is meaningful only
             # on 64 bit, because on 32 bit the ulonglong case would have been
             # handled by the is_longlong() branch above. On 64 bit, ulonglong
diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py
--- a/pypy/module/_minimal_curses/fficurses.py
+++ b/pypy/module/_minimal_curses/fficurses.py
@@ -8,11 +8,20 @@
 from pypy.rpython.extfunc import register_external
 from pypy.module._minimal_curses import interp_curses
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
+from sys import platform
 
-eci = ExternalCompilationInfo(
-    includes = ['curses.h', 'term.h'],
-    libraries = ['curses'],
-)
+_CYGWIN = platform == 'cygwin'
+
+if _CYGWIN:
+    eci = ExternalCompilationInfo(
+        includes = ['ncurses/curses.h', 'ncurses/term.h'],
+        libraries = ['curses'],
+    )
+else:
+    eci = ExternalCompilationInfo(
+        includes = ['curses.h', 'term.h'],
+        libraries = ['curses'],
+    )
 
 rffi_platform.verify_eci(eci)
 
diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py
--- a/pypy/module/_socket/test/test_sock_app.py
+++ b/pypy/module/_socket/test/test_sock_app.py
@@ -611,14 +611,19 @@
         buf = t.recv(1)
         assert buf == '?'
         # test send() timeout
+        count = 0
         try:
             while 1:
-                cli.send('foobar' * 70)
+                count += cli.send('foobar' * 70)
         except timeout:
             pass
-        # test sendall() timeout, be sure to send data larger than the
-        # socket buffer
-        raises(timeout, cli.sendall, 'foobar' * 7000)
+        t.recv(count)    
+        # test sendall() timeout
+        try:
+            while 1:
+                cli.sendall('foobar' * 70)
+        except timeout:
+            pass
         # done
         cli.close()
         t.close()
diff --git a/pypy/module/_ssl/__init__.py b/pypy/module/_ssl/__init__.py
--- a/pypy/module/_ssl/__init__.py
+++ b/pypy/module/_ssl/__init__.py
@@ -31,5 +31,6 @@
     def startup(self, space):
         from pypy.rlib.ropenssl import init_ssl
         init_ssl()
-        from pypy.module._ssl.interp_ssl import setup_ssl_threads
-        setup_ssl_threads()
+        if space.config.objspace.usemodules.thread:
+            from pypy.module._ssl.thread_lock import setup_ssl_threads
+            setup_ssl_threads()
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -789,7 +789,11 @@
 def _ssl_seterror(space, ss, ret):
     assert ret <= 0
 
-    if ss and ss.ssl:
+    if ss is None:
+        errval = libssl_ERR_peek_last_error()
+        errstr = rffi.charp2str(libssl_ERR_error_string(errval, None))
+        return ssl_error(space, errstr, errval)
+    elif ss.ssl:
         err = libssl_SSL_get_error(ss.ssl, ret)
     else:
         err = SSL_ERROR_SSL
@@ -880,38 +884,3 @@
             libssl_X509_free(x)
     finally:
         libssl_BIO_free(cert)
-
-# this function is needed to perform locking on shared data
-# structures. (Note that OpenSSL uses a number of global data
-# structures that will be implicitly shared whenever multiple threads
-# use OpenSSL.) Multi-threaded applications will crash at random if
-# it is not set.
-#
-# locking_function() must be able to handle up to CRYPTO_num_locks()
-# different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
-# releases it otherwise.
-#
-# filename and line are the file number of the function setting the
-# lock. They can be useful for debugging.
-_ssl_locks = []
-
-def _ssl_thread_locking_function(mode, n, filename, line):
-    n = intmask(n)
-    if n < 0 or n >= len(_ssl_locks):
-        return
-
-    if intmask(mode) & CRYPTO_LOCK:
-        _ssl_locks[n].acquire(True)
-    else:
-        _ssl_locks[n].release()
-
-def _ssl_thread_id_function():
-    from pypy.module.thread import ll_thread
-    return rffi.cast(rffi.LONG, ll_thread.get_ident())
-
-def setup_ssl_threads():
-    from pypy.module.thread import ll_thread
-    for i in range(libssl_CRYPTO_num_locks()):
-        _ssl_locks.append(ll_thread.allocate_lock())
-    libssl_CRYPTO_set_locking_callback(_ssl_thread_locking_function)
-    libssl_CRYPTO_set_id_callback(_ssl_thread_id_function)
diff --git a/pypy/module/_ssl/test/test_ztranslation.py b/pypy/module/_ssl/test/test_ztranslation.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ssl/test/test_ztranslation.py
@@ -0,0 +1,4 @@
+from pypy.objspace.fake.checkmodule import checkmodule
+
+def test__ffi_translates():
+    checkmodule('_ssl')
diff --git a/pypy/module/_ssl/thread_lock.py b/pypy/module/_ssl/thread_lock.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ssl/thread_lock.py
@@ -0,0 +1,80 @@
+from pypy.rlib.ropenssl import *
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+
+# CRYPTO_set_locking_callback:
+#
+# this function is needed to perform locking on shared data
+# structures. (Note that OpenSSL uses a number of global data
+# structures that will be implicitly shared whenever multiple threads
+# use OpenSSL.) Multi-threaded applications will crash at random if
+# it is not set.
+#
+# locking_function() must be able to handle up to CRYPTO_num_locks()
+# different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
+# releases it otherwise.
+#
+# filename and line are the file number of the function setting the
+# lock. They can be useful for debugging.
+
+
+# This logic is moved to C code so that the callbacks can be invoked
+# without caring about the GIL.
+
+separate_module_source = """
+
+#include <openssl/crypto.h>
+
+static unsigned int _ssl_locks_count = 0;
+static struct RPyOpaque_ThreadLock *_ssl_locks;
+
+static unsigned long _ssl_thread_id_function(void) {
+    return RPyThreadGetIdent();
+}
+
+static void _ssl_thread_locking_function(int mode, int n, const char *file,
+                                         int line) {
+    if ((_ssl_locks == NULL) ||
+        (n < 0) || ((unsigned)n >= _ssl_locks_count))
+        return;
+
+    if (mode & CRYPTO_LOCK) {
+        RPyThreadAcquireLock(_ssl_locks + n, 1);
+    } else {
+        RPyThreadReleaseLock(_ssl_locks + n);
+    }
+}
+
+int _PyPy_SSL_SetupThreads(void)
+{
+    unsigned int i;
+    _ssl_locks_count = CRYPTO_num_locks();
+    _ssl_locks = calloc(_ssl_locks_count, sizeof(struct RPyOpaque_ThreadLock));
+    if (_ssl_locks == NULL)
+        return 0;
+    for (i=0; i<_ssl_locks_count; i++) {
+        if (RPyThreadLockInit(_ssl_locks + i) == 0)
+            return 0;
+    }
+    CRYPTO_set_locking_callback(_ssl_thread_locking_function);
+    CRYPTO_set_id_callback(_ssl_thread_id_function);
+    return 1;
+}
+"""
+
+
+eci = ExternalCompilationInfo(
+    separate_module_sources=[separate_module_source],
+    post_include_bits=[
+        "int _PyPy_SSL_SetupThreads(void);"],
+    export_symbols=['_PyPy_SSL_SetupThreads'],
+)
+
+_PyPy_SSL_SetupThreads = rffi.llexternal('_PyPy_SSL_SetupThreads',
+                                         [], rffi.INT,
+                                         compilation_info=eci)
+
+def setup_ssl_threads():
+    result = _PyPy_SSL_SetupThreads()
+    if rffi.cast(lltype.Signed, result) == 0:
+        raise MemoryError
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -164,6 +164,8 @@
         data[index] = char
         array._charbuf_stop()
 
+    def get_raw_address(self):
+        return self.array._charbuf_start()
 
 def make_array(mytype):
     W_ArrayBase = globals()['W_ArrayBase']
diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py
--- a/pypy/module/cStringIO/interp_stringio.py
+++ b/pypy/module/cStringIO/interp_stringio.py
@@ -221,7 +221,8 @@
 }
 
 W_InputType.typedef = TypeDef(
-    "cStringIO.StringI",
+    "StringI",
+    __module__   = "cStringIO",
     __doc__      = "Simple type for treating strings as input file streams",
     closed       = GetSetProperty(descr_closed, cls=W_InputType),
     softspace    = GetSetProperty(descr_softspace,
@@ -232,7 +233,8 @@
     )
 
 W_OutputType.typedef = TypeDef(
-    "cStringIO.StringO",
+    "StringO",
+    __module__   = "cStringIO",
     __doc__      = "Simple type for output to strings.",
     truncate     = interp2app(W_OutputType.descr_truncate),
     write        = interp2app(W_OutputType.descr_write),
diff --git a/pypy/module/cppyy/__init__.py b/pypy/module/cppyy/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/__init__.py
@@ -0,0 +1,22 @@
+from pypy.interpreter.mixedmodule import MixedModule
+
+class Module(MixedModule):
+    """    """
+
+    interpleveldefs = {
+        '_load_dictionary'       : 'interp_cppyy.load_dictionary',
+        '_resolve_name'          : 'interp_cppyy.resolve_name',
+        '_scope_byname'          : 'interp_cppyy.scope_byname',
+        '_template_byname'       : 'interp_cppyy.template_byname',
+        '_set_class_generator'   : 'interp_cppyy.set_class_generator',
+        '_register_class'        : 'interp_cppyy.register_class',
+        'CPPInstance'            : 'interp_cppyy.W_CPPInstance',
+        'addressof'              : 'interp_cppyy.addressof',
+        'bind_object'            : 'interp_cppyy.bind_object',
+    }
+
+    appleveldefs = {
+        'gbl'                    : 'pythonify.gbl',
+        'load_reflection_info'   : 'pythonify.load_reflection_info',
+        'add_pythonization'      : 'pythonify.add_pythonization',
+    }
diff --git a/pypy/module/cppyy/bench/Makefile b/pypy/module/cppyy/bench/Makefile
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/Makefile
@@ -0,0 +1,29 @@
+all: bench02Dict_reflex.so
+
+ROOTSYS := ${ROOTSYS}
+
+ifeq ($(ROOTSYS),)
+  genreflex=genreflex
+  cppflags=
+else
+  genreflex=$(ROOTSYS)/bin/genreflex
+  cppflags=-I$(ROOTSYS)/include -L$(ROOTSYS)/lib
+endif
+
+PLATFORM := $(shell uname -s)
+ifeq ($(PLATFORM),Darwin)
+  cppflags+=-dynamiclib -single_module -arch x86_64
+endif
+
+ifeq ($(shell $(genreflex) --help | grep -- --with-methptrgetter),)
+  genreflexflags=
+  cppflags2=-O3 -fPIC
+else
+  genreflexflags=--with-methptrgetter
+  cppflags2=-Wno-pmf-conversions -O3 -fPIC
+endif
+
+
+bench02Dict_reflex.so: bench02.h bench02.cxx bench02.xml
+	$(genreflex) bench02.h $(genreflexflags) --selection=bench02.xml -I$(ROOTSYS)/include
+	g++ -o $@ bench02.cxx bench02_rflx.cpp -I$(ROOTSYS)/include -shared -lReflex -lHistPainter `root-config --libs` $(cppflags) $(cppflags2)
diff --git a/pypy/module/cppyy/bench/bench02.cxx b/pypy/module/cppyy/bench/bench02.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/bench02.cxx
@@ -0,0 +1,79 @@
+#include "bench02.h"
+
+#include "TROOT.h"
+#include "TApplication.h"
+#include "TDirectory.h"
+#include "TInterpreter.h"
+#include "TSystem.h"
+#include "TBenchmark.h"
+#include "TStyle.h"
+#include "TError.h"
+#include "Getline.h"
+#include "TVirtualX.h"
+
+#include "Api.h"
+
+#include <iostream>
+
+TClass *TClass::GetClass(const char*, Bool_t, Bool_t) {
+    static TClass* dummy = new TClass("__dummy__", kTRUE);
+    return dummy;  // is deleted by gROOT at shutdown
+}
+
+class TTestApplication : public TApplication {
+public:
+    TTestApplication(
+        const char* acn, Int_t* argc, char** argv, Bool_t bLoadLibs = kTRUE);
+    virtual ~TTestApplication();
+};
+
+TTestApplication::TTestApplication(
+        const char* acn, int* argc, char** argv, bool do_load) : TApplication(acn, argc, argv) {
+    if (do_load) {
+        // follow TRint to minimize differences with CINT
+        ProcessLine("#include <iostream>", kTRUE);
+        ProcessLine("#include <_string>",  kTRUE); // for std::string iostream.
+        ProcessLine("#include <vector>",   kTRUE); // needed because they're used within the
+        ProcessLine("#include <pair>",     kTRUE); //  core ROOT dicts and CINT won't be able
+                                                   //  to properly unload these files
+    }
+
+    // save current interpreter context
+    gInterpreter->SaveContext();
+    gInterpreter->SaveGlobalsContext();
+
+    // prevent crashes on accessing history
+    Gl_histinit((char*)"-");
+
+    // prevent ROOT from exiting python
+    SetReturnFromRun(kTRUE);
+}
+
+TTestApplication::~TTestApplication() {}
+
+static const char* appname = "pypy-cppyy";
+
+Bench02RootApp::Bench02RootApp() {
+    gROOT->SetBatch(kTRUE);
+    if (!gApplication) {
+        int argc = 1;
+        char* argv[1]; argv[0] = (char*)appname;
+        gApplication = new TTestApplication(appname, &argc, argv, kFALSE);
+    }
+}
+
+Bench02RootApp::~Bench02RootApp() {
+    // TODO: ROOT globals cleanup ... (?)
+}
+
+void Bench02RootApp::report() {
+    std::cout << "gROOT is: " << gROOT << std::endl;
+    std::cout << "gApplication is: " << gApplication << std::endl;
+}
+
+void Bench02RootApp::close_file(TFile* f) {
+    std::cout << "closing file " << f->GetName() << " ... " << std::endl;
+    f->Write();
+    f->Close();
+    std::cout << "... file closed" << std::endl;
+}
diff --git a/pypy/module/cppyy/bench/bench02.h b/pypy/module/cppyy/bench/bench02.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/bench02.h
@@ -0,0 +1,72 @@
+#include "TString.h"
+
+#include "TCanvas.h"
+#include "TFile.h"
+#include "TProfile.h"
+#include "TNtuple.h"
+#include "TH1F.h"
+#include "TH2F.h"
+#include "TRandom.h"
+#include "TRandom3.h"
+
+#include "TROOT.h"
+#include "TApplication.h"
+#include "TSystem.h"
+
+#include "TArchiveFile.h"
+#include "TBasket.h"
+#include "TBenchmark.h"
+#include "TBox.h"
+#include "TBranchRef.h"
+#include "TBrowser.h"
+#include "TClassGenerator.h"
+#include "TClassRef.h"
+#include "TClassStreamer.h"
+#include "TContextMenu.h"
+#include "TEntryList.h"
+#include "TEventList.h"
+#include "TF1.h"
+#include "TFileCacheRead.h"
+#include "TFileCacheWrite.h"
+#include "TFileMergeInfo.h"
+#include "TFitResult.h"
+#include "TFolder.h"
+//#include "TFormulaPrimitive.h"
+#include "TFunction.h"
+#include "TFrame.h"
+#include "TGlobal.h"
+#include "THashList.h"
+#include "TInetAddress.h"
+#include "TInterpreter.h"
+#include "TKey.h"
+#include "TLegend.h"
+#include "TMethodCall.h"
+#include "TPluginManager.h"
+#include "TProcessUUID.h"
+#include "TSchemaRuleSet.h"
+#include "TStyle.h"
+#include "TSysEvtHandler.h"
+#include "TTimer.h"
+#include "TView.h"
+//#include "TVirtualCollectionProxy.h"
+#include "TVirtualFFT.h"
+#include "TVirtualHistPainter.h"
+#include "TVirtualIndex.h"
+#include "TVirtualIsAProxy.h"
+#include "TVirtualPadPainter.h"
+#include "TVirtualRefProxy.h"
+#include "TVirtualStreamerInfo.h"
+#include "TVirtualViewer3D.h"
+
+#include <typeinfo>
+#include <ostream>
+
+
+class Bench02RootApp {
+public:
+   Bench02RootApp();
+   ~Bench02RootApp();
+
+   void report();
+   void close_file(TFile* f);
+};
diff --git a/pypy/module/cppyy/bench/bench02.xml b/pypy/module/cppyy/bench/bench02.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/bench02.xml
@@ -0,0 +1,41 @@
+<lcgdict>
+
+  <selection>
+
+     <!-- ROOT classes -->
+     <class pattern="T[A-Z]*" />
+     <class pattern="ROOT::T[A-Z]*" />
+     <class pattern="ROOT::Fit::*" />
+
+     <!-- ROOT globals -->
+     <variable name="gROOT" />
+     <variable name="gSystem" />
+     <variable name="gRandom" />
+
+     <!-- STL classes actually used -->
+     <class name="std::string" />
+     <class name="std::ostream" />
+     <class name="std::type_info" />
+     <class pattern="std::vector<*>" />
+     <class pattern="std::_Vector_base<*>" />
+
+     <!-- helper -->
+     <class name="Bench02RootApp" />
+
+  </selection>
+
+  <exclusion>
+
+     <struct pattern="TString::*" />
+     <class name="TString" >
+         <field name="fRep" transient="true"/>
+     </class>
+
+     <class name="TUUID::uuid_time_t" />
+
+     <class name="TClass::TNameMapNode" />
+     <class name="TFileOpenHandle" />
+
+  </exclusion>
+
+</lcgdict>
diff --git a/pypy/module/cppyy/bench/hsimple.C b/pypy/module/cppyy/bench/hsimple.C
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/hsimple.C
@@ -0,0 +1,109 @@
+#include <TFile.h>
+#include <TNtuple.h>
+#include <TH2.h>
+#include <TProfile.h>
+#include <TCanvas.h>
+#include <TFrame.h>
+#include <TROOT.h>
+#include <TSystem.h>
+#include <TRandom3.h>
+#include <TBenchmark.h>
+#include <TInterpreter.h>
+
+TFile *hsimple(Int_t get=0)
+{
+//  This program creates :
+//    - a one dimensional histogram
+//    - a two dimensional histogram
+//    - a profile histogram
+//    - a memory-resident ntuple
+//
+//  These objects are filled with some random numbers and saved on a file.
+//  If get=1 the macro returns a pointer to the TFile of "hsimple.root"
+//          if this file exists, otherwise it is created.
+//  The file "hsimple.root" is created in $ROOTSYS/tutorials if the caller has
+//  write access to this directory, otherwise the file is created in $PWD
+
+   TString filename = "hsimple.root";
+   TString dir = gSystem->UnixPathName(gInterpreter->GetCurrentMacroName());
+   dir.ReplaceAll("hsimple.C","");
+   dir.ReplaceAll("/./","/");
+   TFile *hfile = 0;
+   if (get) {
+      // if the argument get =1 return the file "hsimple.root"
+      // if the file does not exist, it is created
+      TString fullPath = dir+"hsimple.root";
+      if (!gSystem->AccessPathName(fullPath,kFileExists)) {
+	 hfile = TFile::Open(fullPath); //in $ROOTSYS/tutorials
+         if (hfile) return hfile;
+      }
+      //otherwise try $PWD/hsimple.root
+      if (!gSystem->AccessPathName("hsimple.root",kFileExists)) {
+         hfile = TFile::Open("hsimple.root"); //in current dir
+         if (hfile) return hfile;
+      }
+   }
+   //no hsimple.root file found. Must generate it !
+   //generate hsimple.root in $ROOTSYS/tutorials if we have write access
+   if (!gSystem->AccessPathName(dir,kWritePermission)) {
+      filename = dir+"hsimple.root";
+   } else if (!gSystem->AccessPathName(".",kWritePermission)) {
+      //otherwise generate hsimple.root in the current directory
+   } else {
+      printf("you must run the script in a directory with write access\n");
+      return 0;
+   }
+   hfile = (TFile*)gROOT->FindObject(filename); if (hfile) hfile->Close();
+   hfile = new TFile(filename,"RECREATE","Demo ROOT file with histograms");
+
+   // Create some histograms, a profile histogram and an ntuple
+   TH1F *hpx = new TH1F("hpx","This is the px distribution",100,-4,4);
+   hpx->SetFillColor(48);
+   TH2F *hpxpy = new TH2F("hpxpy","py vs px",40,-4,4,40,-4,4);
+   TProfile *hprof = new TProfile("hprof","Profile of pz versus px",100,-4,4,0,20);
+   TNtuple *ntuple = new TNtuple("ntuple","Demo ntuple","px:py:pz:random:i");
+
+   gBenchmark->Start("hsimple");
+  
+   // Create a new canvas.
+   TCanvas *c1 = new TCanvas("c1","Dynamic Filling Example",200,10,700,500);
+   c1->SetFillColor(42);
+   c1->GetFrame()->SetFillColor(21);
+   c1->GetFrame()->SetBorderSize(6);
+   c1->GetFrame()->SetBorderMode(-1);
+
+
+   // Fill histograms randomly
+   TRandom3 random;
+   Float_t px, py, pz;
+   const Int_t kUPDATE = 1000;
+   for (Int_t i = 0; i < 50000; i++) {
+   //      random.Rannor(px,py);
+      px = random.Gaus(0, 1);
+      py = random.Gaus(0, 1);
+      pz = px*px + py*py;
+      Float_t rnd = random.Rndm(1);
+      hpx->Fill(px);
+      hpxpy->Fill(px,py);
+      hprof->Fill(px,pz);
+      ntuple->Fill(px,py,pz,rnd,i);
+      if (i && (i%kUPDATE) == 0) {
+         if (i == kUPDATE) hpx->Draw();
+         c1->Modified();
+         c1->Update();
+         if (gSystem->ProcessEvents())
+            break;
+      }
+   }
+   gBenchmark->Show("hsimple");
+
+   // Save all objects in this file
+   hpx->SetFillColor(0);
+   hfile->Write();
+   hpx->SetFillColor(48);
+   c1->Modified();
+   return hfile;
+  
+// Note that the file is automatically close when application terminates
+// or when the file destructor is called.
+}
diff --git a/pypy/module/cppyy/bench/hsimple.py b/pypy/module/cppyy/bench/hsimple.py
new file mode 100755
--- /dev/null
+++ b/pypy/module/cppyy/bench/hsimple.py
@@ -0,0 +1,110 @@
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+#*-*
+#*-*  This program creates :
+#*-*    - a one dimensional histogram
+#*-*    - a two dimensional histogram
+#*-*    - a profile histogram
+#*-*    - a memory-resident ntuple
+#*-*
+#*-*  These objects are filled with some random numbers and saved on a file.
+#*-*
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+
+_reflex = True     # to keep things equal, set to False for full macro
+
+try:
+    import cppyy, random
+
+    if not hasattr(cppyy.gbl, 'gROOT'):
+        cppyy.load_reflection_info('bench02Dict_reflex.so')
+        _reflex = True
+
+    TCanvas  = cppyy.gbl.TCanvas
+    TFile    = cppyy.gbl.TFile
+    TProfile = cppyy.gbl.TProfile
+    TNtuple  = cppyy.gbl.TNtuple
+    TH1F     = cppyy.gbl.TH1F
+    TH2F     = cppyy.gbl.TH2F
+    TRandom3 = cppyy.gbl.TRandom3
+
+    gROOT      = cppyy.gbl.gROOT
+    gBenchmark = cppyy.gbl.TBenchmark()
+    gSystem    = cppyy.gbl.gSystem
+
+except ImportError:
+    from ROOT import TCanvas, TFile, TProfile, TNtuple, TH1F, TH2F, TRandom3
+    from ROOT import gROOT, gBenchmark, gSystem
+    import random
+
+if _reflex:
+   gROOT.SetBatch(True)
+
+# Create a new ROOT binary machine independent file.
+# Note that this file may contain any kind of ROOT objects, histograms,
+# pictures, graphics objects, detector geometries, tracks, events, etc..
+# This file is now becoming the current directory.
+
+if not _reflex:
+    hfile = gROOT.FindObject('hsimple.root')
+    if hfile:
+        hfile.Close()
+    hfile = TFile('hsimple.root', 'RECREATE', 'Demo ROOT file with histograms' )
+
+# Create some histograms, a profile histogram and an ntuple
+hpx    = TH1F('hpx', 'This is the px distribution', 100, -4, 4)
+hpx.SetFillColor(48)
+hpxpy  = TH2F('hpxpy', 'py vs px', 40, -4, 4, 40, -4, 4)
+hprof  = TProfile('hprof', 'Profile of pz versus px', 100, -4, 4, 0, 20)
+if not _reflex:
+    ntuple = TNtuple('ntuple', 'Demo ntuple', 'px:py:pz:random:i')
+
+gBenchmark.Start('hsimple')
+
+# Create a new canvas, and customize it.
+c1 = TCanvas('c1', 'Dynamic Filling Example', 200, 10, 700, 500)
+c1.SetFillColor(42)
+c1.GetFrame().SetFillColor(21)
+c1.GetFrame().SetBorderSize(6)
+c1.GetFrame().SetBorderMode(-1)
+
+# Fill histograms randomly.
+random = TRandom3()
+kUPDATE = 1000
+for i in xrange(50000):
+    # Generate random numbers
+#    px, py = random.gauss(0, 1), random.gauss(0, 1)
+    px, py = random.Gaus(0, 1), random.Gaus(0, 1)
+    pz = px*px + py*py
+#    rnd = random.random()
+    rnd = random.Rndm(1)
+
+    # Fill histograms
+    hpx.Fill(px)
+    hpxpy.Fill(px, py)
+    hprof.Fill(px, pz)
+    if not _reflex:
+        ntuple.Fill(px, py, pz, rnd, i)
+
+    # Update display every kUPDATE events
+    if i and i%kUPDATE == 0:
+        if i == kUPDATE:
+            hpx.Draw()
+
+        c1.Modified(True)
+        c1.Update()
+
+        if gSystem.ProcessEvents():          # allow user interrupt
+            break
+
+gBenchmark.Show( 'hsimple' )
+
+# Save all objects in this file
+hpx.SetFillColor(0)
+if not _reflex:
+    hfile.Write()
+hpx.SetFillColor(48)
+c1.Modified(True)
+c1.Update()
+
+# Note that the file is automatically closed when application terminates
+# or when the file destructor is called.
diff --git a/pypy/module/cppyy/bench/hsimple_rflx.py b/pypy/module/cppyy/bench/hsimple_rflx.py
new file mode 100755
--- /dev/null
+++ b/pypy/module/cppyy/bench/hsimple_rflx.py
@@ -0,0 +1,120 @@
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+#*-*
+#*-*  This program creates :
+#*-*    - a one dimensional histogram
+#*-*    - a two dimensional histogram
+#*-*    - a profile histogram
+#*-*    - a memory-resident ntuple
+#*-*
+#*-*  These objects are filled with some random numbers and saved on a file.
+#*-*
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+
+try:
+    import warnings
+    warnings.simplefilter("ignore")
+
+    import cppyy, random
+    cppyy.load_reflection_info('bench02Dict_reflex.so')
+
+    app      = cppyy.gbl.Bench02RootApp()
+    TCanvas  = cppyy.gbl.TCanvas
+    TFile    = cppyy.gbl.TFile
+    TProfile = cppyy.gbl.TProfile
+    TNtuple  = cppyy.gbl.TNtuple
+    TH1F     = cppyy.gbl.TH1F
+    TH2F     = cppyy.gbl.TH2F
+    TRandom  = cppyy.gbl.TRandom
+except ImportError:
+    from ROOT import TCanvas, TFile, TProfile, TNtuple, TH1F, TH2F, TRandom
+    import random
+
+import math
+
+#gROOT      = cppyy.gbl.gROOT
+#gBenchmark = cppyy.gbl.gBenchmark
+#gRandom    = cppyy.gbl.gRandom
+#gSystem    = cppyy.gbl.gSystem
+
+#gROOT.Reset()
+
+# Create a new canvas, and customize it.
+#c1 = TCanvas( 'c1', 'Dynamic Filling Example', 200, 10, 700, 500 )
+#c1.SetFillColor( 42 )
+#c1.GetFrame().SetFillColor( 21 )
+#c1.GetFrame().SetBorderSize( 6 )
+#c1.GetFrame().SetBorderMode( -1 )
+
+# Create a new ROOT binary machine independent file.
+# Note that this file may contain any kind of ROOT objects, histograms,
+# pictures, graphics objects, detector geometries, tracks, events, etc..
+# This file is now becoming the current directory.
+
+#hfile = gROOT.FindObject( 'hsimple.root' )
+#if hfile:
+#   hfile.Close()
+#hfile = TFile( 'hsimple.root', 'RECREATE', 'Demo ROOT file with histograms' )
+
+# Create some histograms, a profile histogram and an ntuple
+hpx    = TH1F('hpx', 'This is the px distribution', 100, -4, 4)
+hpx.Print()
+#hpxpy  = TH2F( 'hpxpy', 'py vs px', 40, -4, 4, 40, -4, 4 )
+#hprof  = TProfile( 'hprof', 'Profile of pz versus px', 100, -4, 4, 0, 20 )
+#ntuple = TNtuple( 'ntuple', 'Demo ntuple', 'px:py:pz:random:i' )
+
+# Set canvas/frame attributes.
+#hpx.SetFillColor( 48 )
+
+#gBenchmark.Start( 'hsimple' )
+
+# Initialize random number generator.
+#gRandom.SetSeed()
+#rannor, rndm = gRandom.Rannor, gRandom.Rndm
+
+random = TRandom()
+random.SetSeed(0)
+
+# Fill histograms randomly.
+#px, py = Double(), Double()
+kUPDATE = 1000
+for i in xrange(2500000):
+ # Generate random values.
+#   px, py = random.gauss(0, 1), random.gauss(0, 1)
+   px, py = random.Gaus(0, 1), random.Gaus(0, 1)
+#   pt = (px*px + py*py)**0.5
+   pt = math.sqrt(px*px + py*py)
+#   pt = (px*px + py*py)
+#   random = rndm(1)
+
+ # Fill histograms.
+   hpx.Fill(pt)
+#   hpxpyFill( px, py )
+#   hprofFill( px, pz )
+#   ntupleFill( px, py, pz, random, i )
+
+ # Update display every kUPDATE events.
+#   if i and i%kUPDATE == 0:
+#      if i == kUPDATE:
+#         hpx.Draw()
+
+#      c1.Modified()
+#      c1.Update()
+
+#      if gSystem.ProcessEvents():            # allow user interrupt
+#         break
+
+#gBenchmark.Show( 'hsimple' )
+
+hpx.Print() 
+
+# Save all objects in this file.
+#hpx.SetFillColor( 0 )
+#hfile.Write()
+#hfile.Close()
+#hpx.SetFillColor( 48 )
+#c1.Modified()
+#c1.Update()
+#c1.Draw()
+
+# Note that the file is automatically closed when application terminates
+# or when the file destructor is called.
diff --git a/pypy/module/cppyy/capi/__init__.py b/pypy/module/cppyy/capi/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/__init__.py
@@ -0,0 +1,450 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib import jit
+
+import reflex_capi as backend
+#import cint_capi as backend
+
+identify = backend.identify
+ts_reflect = backend.ts_reflect
+ts_call    = backend.ts_call
+ts_memory  = backend.ts_memory
+ts_helper  = backend.ts_helper
+
+_C_OPAQUE_PTR = rffi.LONG
+_C_OPAQUE_NULL = lltype.nullptr(rffi.LONGP.TO)# ALT: _C_OPAQUE_PTR.TO
+
+C_SCOPE = _C_OPAQUE_PTR
+C_NULL_SCOPE = rffi.cast(C_SCOPE, _C_OPAQUE_NULL)
+
+C_TYPE = C_SCOPE
+C_NULL_TYPE = C_NULL_SCOPE
+
+C_OBJECT = _C_OPAQUE_PTR
+C_NULL_OBJECT = rffi.cast(C_OBJECT, _C_OPAQUE_NULL)
+
+C_METHOD = _C_OPAQUE_PTR
+
+C_METHPTRGETTER = lltype.FuncType([C_OBJECT], rffi.VOIDP)
+C_METHPTRGETTER_PTR = lltype.Ptr(C_METHPTRGETTER)
+
+def direct_ptradd(ptr, offset):
+    offset = rffi.cast(rffi.SIZE_T, offset)
+    jit.promote(offset)
+    assert lltype.typeOf(ptr) == C_OBJECT
+    address = rffi.cast(rffi.CCHARP, ptr)
+    return rffi.cast(C_OBJECT, lltype.direct_ptradd(address, offset))
+
+c_load_dictionary = backend.c_load_dictionary
+
+# name to opaque C++ scope representation ------------------------------------
+_c_resolve_name = rffi.llexternal(
+    "cppyy_resolve_name",
+    [rffi.CCHARP], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_resolve_name(name):
+    return charp2str_free(_c_resolve_name(name))
+c_get_scope_opaque = rffi.llexternal(
+    "cppyy_get_scope",
+    [rffi.CCHARP], C_SCOPE,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+c_get_template = rffi.llexternal(
+    "cppyy_get_template",
+    [rffi.CCHARP], C_TYPE,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+_c_actual_class = rffi.llexternal(
+    "cppyy_actual_class",
+    [C_TYPE, C_OBJECT], C_TYPE,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_actual_class(cppclass, cppobj):
+    return _c_actual_class(cppclass.handle, cppobj)
+
+# memory management ----------------------------------------------------------
+_c_allocate = rffi.llexternal(
+    "cppyy_allocate",
+    [C_TYPE], C_OBJECT,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci)
+def c_allocate(cppclass):
+    return _c_allocate(cppclass.handle)
+_c_deallocate = rffi.llexternal(
+    "cppyy_deallocate",
+    [C_TYPE, C_OBJECT], lltype.Void,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci)
+def c_deallocate(cppclass, cppobject):
+    _c_deallocate(cppclass.handle, cppobject)
+_c_destruct = rffi.llexternal(
+    "cppyy_destruct",
+    [C_TYPE, C_OBJECT], lltype.Void,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+def c_destruct(cppclass, cppobject):
+    _c_destruct(cppclass.handle, cppobject)
+
+# method/function dispatching ------------------------------------------------
+c_call_v = rffi.llexternal(
+    "cppyy_call_v",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], lltype.Void,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_b = rffi.llexternal(
+    "cppyy_call_b",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_c = rffi.llexternal(
+    "cppyy_call_c",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.CHAR,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_h = rffi.llexternal(
+    "cppyy_call_h",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.SHORT,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_i = rffi.llexternal(
+    "cppyy_call_i",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_l = rffi.llexternal(
+    "cppyy_call_l",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.LONG,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_ll = rffi.llexternal(
+    "cppyy_call_ll",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.LONGLONG,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_f = rffi.llexternal(
+    "cppyy_call_f",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_d = rffi.llexternal(
+    "cppyy_call_d",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+
+c_call_r = rffi.llexternal(
+    "cppyy_call_r",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.VOIDP,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_s = rffi.llexternal(
+    "cppyy_call_s",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.CCHARP,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+
+c_constructor = rffi.llexternal(
+    "cppyy_constructor",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], lltype.Void,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+
+_c_call_o = rffi.llexternal(
+    "cppyy_call_o",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP, C_TYPE], rffi.LONG,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+def c_call_o(method_index, cppobj, nargs, args, cppclass):
+    return _c_call_o(method_index, cppobj, nargs, args, cppclass.handle)
+
+_c_get_methptr_getter = rffi.llexternal(
+    "cppyy_get_methptr_getter",
+    [C_SCOPE, rffi.INT], C_METHPTRGETTER_PTR,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci,
+    elidable_function=True)
+def c_get_methptr_getter(cppscope, method_index):
+    return _c_get_methptr_getter(cppscope.handle, method_index)
+
+# handling of function argument buffer ---------------------------------------
+c_allocate_function_args = rffi.llexternal(
+    "cppyy_allocate_function_args",
+    [rffi.SIZE_T], rffi.VOIDP,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci)
+c_deallocate_function_args = rffi.llexternal(
+    "cppyy_deallocate_function_args",
+    [rffi.VOIDP], lltype.Void,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci)
+c_function_arg_sizeof = rffi.llexternal(
+    "cppyy_function_arg_sizeof",
+    [], rffi.SIZE_T,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci,
+    elidable_function=True)
+c_function_arg_typeoffset = rffi.llexternal(
+    "cppyy_function_arg_typeoffset",
+    [], rffi.SIZE_T,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci,
+    elidable_function=True)
+
+# scope reflection information -----------------------------------------------
+c_is_namespace = rffi.llexternal(
+    "cppyy_is_namespace",
+    [C_SCOPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+c_is_enum = rffi.llexternal(
+    "cppyy_is_enum",
+    [rffi.CCHARP], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+
+# type/class reflection information ------------------------------------------
+_c_final_name = rffi.llexternal(
+    "cppyy_final_name",
+    [C_TYPE], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_final_name(cpptype):
+    return charp2str_free(_c_final_name(cpptype))
+_c_scoped_final_name = rffi.llexternal(
+    "cppyy_scoped_final_name",
+    [C_TYPE], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_scoped_final_name(cpptype):
+    return charp2str_free(_c_scoped_final_name(cpptype))
+c_has_complex_hierarchy = rffi.llexternal(
+    "cppyy_has_complex_hierarchy",
+    [C_TYPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+_c_num_bases = rffi.llexternal(
+    "cppyy_num_bases",
+    [C_TYPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_num_bases(cppclass):
+    return _c_num_bases(cppclass.handle)
+_c_base_name = rffi.llexternal(
+    "cppyy_base_name",
+    [C_TYPE, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_base_name(cppclass, base_index):
+    return charp2str_free(_c_base_name(cppclass.handle, base_index))
+
+_c_is_subtype = rffi.llexternal(
+    "cppyy_is_subtype",
+    [C_TYPE, C_TYPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci,
+    elidable_function=True)
+ at jit.elidable_promote()
+def c_is_subtype(derived, base):
+    if derived == base:
+        return 1
+    return _c_is_subtype(derived.handle, base.handle)
+
+_c_base_offset = rffi.llexternal(
+    "cppyy_base_offset",
+    [C_TYPE, C_TYPE, C_OBJECT, rffi.INT], rffi.SIZE_T,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci,
+    elidable_function=True)
+ at jit.elidable_promote()
+def c_base_offset(derived, base, address, direction):
+    if derived == base:
+        return 0
+    return _c_base_offset(derived.handle, base.handle, address, direction)
+
+# method/function reflection information -------------------------------------
+_c_num_methods = rffi.llexternal(
+    "cppyy_num_methods",
+    [C_SCOPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_num_methods(cppscope):
+    return _c_num_methods(cppscope.handle)
+_c_method_name = rffi.llexternal(
+    "cppyy_method_name",
+    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_name(cppscope, method_index):
+    return charp2str_free(_c_method_name(cppscope.handle, method_index))
+_c_method_result_type = rffi.llexternal(
+    "cppyy_method_result_type",
+    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_result_type(cppscope, method_index):
+    return charp2str_free(_c_method_result_type(cppscope.handle, method_index))
+_c_method_num_args = rffi.llexternal(
+    "cppyy_method_num_args",
+    [C_SCOPE, rffi.INT], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_num_args(cppscope, method_index):
+    return _c_method_num_args(cppscope.handle, method_index)
+_c_method_req_args = rffi.llexternal(
+    "cppyy_method_req_args",
+    [C_SCOPE, rffi.INT], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_req_args(cppscope, method_index):
+    return _c_method_req_args(cppscope.handle, method_index)
+_c_method_arg_type = rffi.llexternal(
+    "cppyy_method_arg_type",
+    [C_SCOPE, rffi.INT, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_arg_type(cppscope, method_index, arg_index):
+    return charp2str_free(_c_method_arg_type(cppscope.handle, method_index, arg_index))
+_c_method_arg_default = rffi.llexternal(
+    "cppyy_method_arg_default",
+    [C_SCOPE, rffi.INT, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_arg_default(cppscope, method_index, arg_index):
+    return charp2str_free(_c_method_arg_default(cppscope.handle, method_index, arg_index))
+_c_method_signature = rffi.llexternal(
+    "cppyy_method_signature",
+    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_signature(cppscope, method_index):
+    return charp2str_free(_c_method_signature(cppscope.handle, method_index))
+
+_c_method_index = rffi.llexternal(
+    "cppyy_method_index",
+    [C_SCOPE, rffi.CCHARP], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_index(cppscope, name):
+    return _c_method_index(cppscope.handle, name)
+
+_c_get_method = rffi.llexternal(
+    "cppyy_get_method",
+    [C_SCOPE, rffi.INT], C_METHOD,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_get_method(cppscope, method_index):
+    return _c_get_method(cppscope.handle, method_index)
+
+# method properties ----------------------------------------------------------
+_c_is_constructor = rffi.llexternal(
+    "cppyy_is_constructor",
+    [C_TYPE, rffi.INT], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_is_constructor(cppclass, method_index):
+    return _c_is_constructor(cppclass.handle, method_index)
+_c_is_staticmethod = rffi.llexternal(
+    "cppyy_is_staticmethod",
+    [C_TYPE, rffi.INT], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_is_staticmethod(cppclass, method_index):
+    return _c_is_staticmethod(cppclass.handle, method_index)
+
+# data member reflection information -----------------------------------------
+_c_num_datamembers = rffi.llexternal(
+    "cppyy_num_datamembers",
+    [C_SCOPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_num_datamembers(cppscope):
+    return _c_num_datamembers(cppscope.handle)
+_c_datamember_name = rffi.llexternal(
+    "cppyy_datamember_name",
+    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_datamember_name(cppscope, datamember_index):
+    return charp2str_free(_c_datamember_name(cppscope.handle, datamember_index))
+_c_datamember_type = rffi.llexternal(
+    "cppyy_datamember_type",
+    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_datamember_type(cppscope, datamember_index):
+    return charp2str_free(_c_datamember_type(cppscope.handle, datamember_index))
+_c_datamember_offset = rffi.llexternal(
+    "cppyy_datamember_offset",
+    [C_SCOPE, rffi.INT], rffi.SIZE_T,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_datamember_offset(cppscope, datamember_index):
+    return _c_datamember_offset(cppscope.handle, datamember_index)
+
+_c_datamember_index = rffi.llexternal(
+    "cppyy_datamember_index",
+    [C_SCOPE, rffi.CCHARP], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_datamember_index(cppscope, name):
+    return _c_datamember_index(cppscope.handle, name)
+
+# data member properties -----------------------------------------------------
+_c_is_publicdata = rffi.llexternal(
+    "cppyy_is_publicdata",
+    [C_SCOPE, rffi.INT], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_is_publicdata(cppscope, datamember_index):
+    return _c_is_publicdata(cppscope.handle, datamember_index)
+_c_is_staticdata = rffi.llexternal(
+    "cppyy_is_staticdata",
+    [C_SCOPE, rffi.INT], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_is_staticdata(cppscope, datamember_index):
+    return _c_is_staticdata(cppscope.handle, datamember_index)
+
+# misc helpers ---------------------------------------------------------------
+c_strtoll = rffi.llexternal(
+    "cppyy_strtoll",
+    [rffi.CCHARP], rffi.LONGLONG,
+    threadsafe=ts_helper,
+    compilation_info=backend.eci)
+c_strtoull = rffi.llexternal(
+    "cppyy_strtoull",
+    [rffi.CCHARP], rffi.ULONGLONG,
+    threadsafe=ts_helper,
+    compilation_info=backend.eci)
+c_free = rffi.llexternal(
+    "cppyy_free",
+    [rffi.VOIDP], lltype.Void,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci)
+
+def charp2str_free(charp):
+    string = rffi.charp2str(charp)
+    voidp = rffi.cast(rffi.VOIDP, charp)
+    c_free(voidp)
+    return string
+
+c_charp2stdstring = rffi.llexternal(
+    "cppyy_charp2stdstring",
+    [rffi.CCHARP], C_OBJECT,
+    threadsafe=ts_helper,
+    compilation_info=backend.eci)
+c_stdstring2stdstring = rffi.llexternal(
+    "cppyy_stdstring2stdstring",
+    [C_OBJECT], C_OBJECT,
+    threadsafe=ts_helper,
+    compilation_info=backend.eci)
+c_assign2stdstring = rffi.llexternal(
+    "cppyy_assign2stdstring",
+    [C_OBJECT, rffi.CCHARP], lltype.Void,
+    threadsafe=ts_helper,
+    compilation_info=backend.eci)
+c_free_stdstring = rffi.llexternal(
+    "cppyy_free_stdstring",
+    [C_OBJECT], lltype.Void,
+    threadsafe=ts_helper,
+    compilation_info=backend.eci)
diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/cint_capi.py
@@ -0,0 +1,63 @@
+import py, os
+
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib import libffi, rdynload
+
+__all__ = ['identify', 'eci', 'c_load_dictionary']
+
+pkgpath = py.path.local(__file__).dirpath().join(os.pardir)
+srcpath = pkgpath.join("src")
+incpath = pkgpath.join("include")
+
+if os.environ.get("ROOTSYS"):
+    import commands
+    (stat, incdir) = commands.getstatusoutput("root-config --incdir")
+    if stat != 0:        # presumably Reflex-only
+        rootincpath = [os.path.join(os.environ["ROOTSYS"], "include")]
+        rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
+    else:
+        rootincpath = [incdir]
+        rootlibpath = commands.getoutput("root-config --libdir").split()
+else:
+    rootincpath = []
+    rootlibpath = []
+
+def identify():
+    return 'CINT'
+
+ts_reflect = False
+ts_call    = False
+ts_memory  = 'auto'
+ts_helper  = 'auto'
+
+# force loading in global mode of core libraries, rather than linking with
+# them as PyPy uses various version of dlopen in various places; note that
+# this isn't going to fly on Windows (note that locking them in objects and
+# calling dlclose in __del__ seems to come too late, so this'll do for now)
+with rffi.scoped_str2charp('libCint.so') as ll_libname:
+    _cintdll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
+with rffi.scoped_str2charp('libCore.so') as ll_libname:
+    _coredll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
+
+eci = ExternalCompilationInfo(
+    separate_module_files=[srcpath.join("cintcwrapper.cxx")],
+    include_dirs=[incpath] + rootincpath,
+    includes=["cintcwrapper.h"],
+    library_dirs=rootlibpath,
+    link_extra=["-lCore", "-lCint"],
+    use_cpp_linker=True,
+)
+
+_c_load_dictionary = rffi.llexternal(
+    "cppyy_load_dictionary",
+    [rffi.CCHARP], rdynload.DLLHANDLE,
+    threadsafe=False,
+    compilation_info=eci)
+
+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
diff --git a/pypy/module/cppyy/capi/reflex_capi.py b/pypy/module/cppyy/capi/reflex_capi.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/reflex_capi.py
@@ -0,0 +1,43 @@
+import py, os
+
+from pypy.rlib import libffi
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+
+__all__ = ['identify', 'eci', 'c_load_dictionary']
+
+pkgpath = py.path.local(__file__).dirpath().join(os.pardir)
+srcpath = pkgpath.join("src")
+incpath = pkgpath.join("include")
+
+if os.environ.get("ROOTSYS"):
+    import commands
+    (stat, incdir) = commands.getstatusoutput("root-config --incdir")
+    if stat != 0:        # presumably Reflex-only
+        rootincpath = [os.path.join(os.environ["ROOTSYS"], "include")]
+        rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
+    else:
+        rootincpath = [incdir]
+        rootlibpath = commands.getoutput("root-config --libdir").split()
+else:
+    rootincpath = []
+    rootlibpath = []
+
+def identify():
+    return 'Reflex'
+
+ts_reflect = False
+ts_call    = 'auto'
+ts_memory  = 'auto'
+ts_helper  = 'auto'
+
+eci = ExternalCompilationInfo(
+    separate_module_files=[srcpath.join("reflexcwrapper.cxx")],
+    include_dirs=[incpath] + rootincpath,
+    includes=["reflexcwrapper.h"],
+    library_dirs=rootlibpath,
+    link_extra=["-lReflex"],
+    use_cpp_linker=True,
+)
+
+def c_load_dictionary(name):
+    return libffi.CDLL(name)
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,832 @@
+import sys
+
+from pypy.interpreter.error import OperationError
+
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib.rarithmetic import r_singlefloat
+from pypy.rlib import jit, libffi, clibffi, rfloat
+
+from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+from pypy.module._rawffi.array import W_Array
+
+from pypy.module.cppyy import helper, capi
+
+
+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
+
+
+class TypeConverter(object):
+    _immutable_ = True
+    libffitype = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+    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 OperationError(space.w_TypeError, space.wrap("no converter available"))
+
+    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):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+    def default_argument_libffi(self, space, argchain):
+        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, unpack_simple_shape(self.space, self.space.wrap(typecode)))
+            setattr(self, name, arr)
+            return arr
+        raise AttributeError(name)
+
+    def _freeze_(self):
+        return True
+
+class ArrayTypeConverterMixin(object):
+    _mixin_ = True
+    _immutable_ = True
+
+    def __init__(self, space, array_size):
+        if array_size <= 0:
+            self.size = sys.maxint
+        else:
+            self.size = array_size
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        # 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.buffer_w(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_ = True
+
+    def __init__(self, space, array_size):
+        self.size = sys.maxint
+
+    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.buffer_w(w_value)
+        try:
+            byteptr[0] = buf.get_raw_address()
+        except ValueError:
+            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 default_argument_libffi(self, space, argchain):
+        argchain.arg(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 space.wrap(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_ = True
+    uses_local = True
+
+    def convert_argument_libffi(self, space, w_obj, argchain, 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)
+
+class IntTypeConverterMixin(NumericTypeConverterMixin):
+    _mixin_ = True
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self._unwrap_object(space, w_obj)
+
+class FloatTypeConverterMixin(NumericTypeConverterMixin):
+    _mixin_ = True
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self._unwrap_object(space, w_obj)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = self.typecode
+
+
+class VoidConverter(TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.void
+
+    def __init__(self, space, name):
+        self.name = name
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        raise OperationError(space.w_TypeError,
+                             space.wrap('no converter available for type "%s"' % self.name))
+
+
+class BoolConverter(TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.schar
+
+    def _unwrap_object(self, space, w_obj):
+        arg = space.c_int_w(w_obj)
+        if arg != False and arg != True:
+            raise OperationError(space.w_ValueError,
+                                 space.wrap("boolean value should be bool, or integer 1 or 0"))
+        return arg
+
+    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 from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+        if address[0] == '\x01':
+            return space.w_True
+        return space.w_False
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+        arg = self._unwrap_object(space, w_value)
+        if arg:
+            address[0] = '\x01'
+        else:
+            address[0] = '\x00'
+
+class CharConverter(TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.schar
+
+    def _unwrap_object(self, space, w_value):
+        # allow int to pass to char and make sure that str is of length 1
+        if space.isinstance_w(w_value, space.w_int):
+            ival = space.c_int_w(w_value)
+            if ival < 0 or 256 <= ival:
+                raise OperationError(space.w_ValueError,
+                                     space.wrap("char arg not in range(256)"))
+
+            value = rffi.cast(rffi.CHAR, space.c_int_w(w_value))
+        else:
+            value = space.str_w(w_value)
+
+        if len(value) != 1:  
+            raise OperationError(space.w_ValueError,
+                                 space.wrap("char expected, got string of size %d" % len(value)))
+        return value[0] # turn it into a "char" to the annotator
+
+    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 from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+        return space.wrap(address[0])
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+        address[0] = self._unwrap_object(space, w_value)
+
+
+class ShortConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.sshort
+    c_type     = rffi.SHORT
+    c_ptrtype  = rffi.SHORTP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(rffi.SHORT, capi.c_strtoll(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(rffi.SHORT, space.int_w(w_obj))
+
+class ConstShortRefConverter(ConstRefNumericTypeConverterMixin, ShortConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+class UnsignedShortConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.sshort
+    c_type     = rffi.USHORT
+    c_ptrtype  = rffi.USHORTP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(self.c_type, space.int_w(w_obj))
+
+class ConstUnsignedShortRefConverter(ConstRefNumericTypeConverterMixin, UnsignedShortConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+class IntConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.sint
+    c_type     = rffi.INT
+    c_ptrtype  = rffi.INTP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(self.c_type, space.c_int_w(w_obj))
+
+class ConstIntRefConverter(ConstRefNumericTypeConverterMixin, IntConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+class UnsignedIntConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.uint
+    c_type     = rffi.UINT
+    c_ptrtype  = rffi.UINTP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(self.c_type, space.uint_w(w_obj))
+
+class ConstUnsignedIntRefConverter(ConstRefNumericTypeConverterMixin, UnsignedIntConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+class LongConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.slong
+    c_type     = rffi.LONG
+    c_ptrtype  = rffi.LONGP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return space.int_w(w_obj)
+
+class ConstLongRefConverter(ConstRefNumericTypeConverterMixin, LongConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+    typecode = 'r'
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self._unwrap_object(space, w_obj)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = self.typecode
+
+class LongLongConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.slong
+    c_type     = rffi.LONGLONG
+    c_ptrtype  = rffi.LONGLONGP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return space.r_longlong_w(w_obj)
+
+class ConstLongLongRefConverter(ConstRefNumericTypeConverterMixin, LongLongConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+    typecode = 'r'
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self._unwrap_object(space, w_obj)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = self.typecode
+
+class UnsignedLongConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.ulong
+    c_type     = rffi.ULONG
+    c_ptrtype  = rffi.ULONGP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return space.uint_w(w_obj)
+
+class ConstUnsignedLongRefConverter(ConstRefNumericTypeConverterMixin, UnsignedLongConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+class UnsignedLongLongConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.ulong
+    c_type     = rffi.ULONGLONG
+    c_ptrtype  = rffi.ULONGLONGP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return space.r_ulonglong_w(w_obj)
+
+class ConstUnsignedLongLongRefConverter(ConstRefNumericTypeConverterMixin, UnsignedLongLongConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+
+class FloatConverter(FloatTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.float
+    c_type     = rffi.FLOAT
+    c_ptrtype  = rffi.FLOATP
+    typecode   = 'f'
+
+    def __init__(self, space, default):
+        if default:
+            fval = float(rfloat.rstring_to_float(default))
+        else:
+            fval = float(0.)
+        self.default = r_singlefloat(fval)
+
+    def _unwrap_object(self, space, w_obj):
+        return r_singlefloat(space.float_w(w_obj))
+
+    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 space.wrap(float(rffiptr[0]))
+
+class ConstFloatRefConverter(FloatConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+    typecode = 'F'
+
+    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+class DoubleConverter(FloatTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.double
+    c_type     = rffi.DOUBLE
+    c_ptrtype  = rffi.DOUBLEP
+    typecode   = 'd'
+
+    def __init__(self, space, default):
+        if default:
+            self.default = rffi.cast(self.c_type, rfloat.rstring_to_float(default))
+        else:
+            self.default = rffi.cast(self.c_type, 0.)
+
+    def _unwrap_object(self, space, w_obj):
+        return space.float_w(w_obj)
+
+class ConstDoubleRefConverter(ConstRefNumericTypeConverterMixin, DoubleConverter):
+    _immutable_ = True
+    libffitype = 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)
+        x[0] = rffi.cast(rffi.LONG, rffi.str2charp(arg))
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'o'
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = self._get_raw_address(space, w_obj, offset)
+        charpptr = rffi.cast(rffi.CCHARPP, address)
+        return space.wrap(rffi.charp2str(charpptr[0]))
+
+    def free_argument(self, space, arg, call_local):
+        lltype.free(rffi.cast(rffi.CCHARPP, arg)[0], flavor='raw')
+
+
+class VoidPtrConverter(TypeConverter):
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'a'
+
+    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+        argchain.arg(get_rawobject(space, w_obj))
+
+class VoidPtrPtrConverter(TypeConverter):
+    _immutable_ = True
+    uses_local = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        r = rffi.cast(rffi.VOIDPP, call_local)
+        r[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, call_local)
+        address = rffi.cast(capi.C_OBJECT, address)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'a'
+
+    def finalize_call(self, space, w_obj, call_local):
+        r = rffi.cast(rffi.VOIDPP, call_local)
+        set_rawobject(space, w_obj, r[0])
+
+class VoidPtrRefConverter(TypeConverter):
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'r'
+
+
+class InstancePtrConverter(TypeConverter):
+    _immutable_ = True
+
+    def __init__(self, space, cppclass):
+        from pypy.module.cppyy.interp_cppyy import W_CPPClass
+        assert isinstance(cppclass, W_CPPClass)
+        self.cppclass = cppclass
+
+    def _unwrap_object(self, space, w_obj):
+        from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+        obj = space.interpclass_w(w_obj)
+        if isinstance(obj, W_CPPInstance):
+            if capi.c_is_subtype(obj.cppclass, self.cppclass):
+                rawobject = obj.get_rawobject()
+                offset = capi.c_base_offset(obj.cppclass, self.cppclass, rawobject, 1)
+                obj_address = capi.direct_ptradd(rawobject, offset)
+                return rffi.cast(capi.C_OBJECT, obj_address)
+        raise OperationError(space.w_TypeError,
+                             space.wrap("cannot pass %s as %s" %
+                             (space.type(w_obj).getname(space, "?"), self.cppclass.name)))
+
+    def convert_argument(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))
+        address = rffi.cast(capi.C_OBJECT, address)
+        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 from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
+        from pypy.module.cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppobject_nocast(
+            space, w_pycppclass, self.cppclass, address, isref=True, python_owns=False)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        address = rffi.cast(rffi.VOIDPP, 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 from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
+        from pypy.module.cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppobject_nocast(
+            space, w_pycppclass, self.cppclass, address, isref=False, python_owns=False)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        self._is_abstract(space)
+
+class InstancePtrPtrConverter(InstancePtrConverter):
+    _immutable_ = True
+    uses_local = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        r = rffi.cast(rffi.VOIDPP, call_local)
+        r[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, call_local)
+        address = rffi.cast(capi.C_OBJECT, address)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'o'
+
+    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):
+        from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+        obj = space.interpclass_w(w_obj)
+        assert isinstance(obj, W_CPPInstance)
+        r = rffi.cast(rffi.VOIDPP, call_local)
+        obj._rawobject = rffi.cast(capi.C_OBJECT, r[0])
+
+
+class StdStringConverter(InstanceConverter):
+    _immutable_ = True
+
+    def __init__(self, space, extra):
+        from pypy.module.cppyy import interp_cppyy
+        cppclass = interp_cppyy.scope_byname(space, "std::string")
+        InstanceConverter.__init__(self, space, cppclass)
+
+    def _unwrap_object(self, space, w_obj):
+        try:
+           charp = rffi.str2charp(space.str_w(w_obj))
+           arg = capi.c_charp2stdstring(charp)
+           rffi.free_charp(charp)
+           return arg
+        except OperationError:
+           arg = InstanceConverter._unwrap_object(self, space, w_obj)
+           return capi.c_stdstring2stdstring(arg)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        try:
+            address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
+            charp = rffi.str2charp(space.str_w(w_value))
+            capi.c_assign2stdstring(address, charp)
+            rffi.free_charp(charp)
+            return
+        except Exception:
+            pass
+        return InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
+
+    def free_argument(self, space, arg, call_local):
+        capi.c_free_stdstring(rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
+
+class StdStringRefConverter(InstancePtrConverter):
+    _immutable_ = True
+
+    def __init__(self, space, extra):
+        from pypy.module.cppyy import interp_cppyy
+        cppclass = interp_cppyy.scope_byname(space, "std::string")
+        InstancePtrConverter.__init__(self, space, cppclass)
+
+
+class PyObjectConverter(TypeConverter):
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        space.getbuiltinmodule("cpyext")
+        from pypy.module.cpyext.pyobject import make_ref
+        ref = make_ref(space, w_obj)
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, ref);
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'a'
+
+    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+        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))
+
+    def free_argument(self, space, arg, call_local):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        from pypy.module.cpyext.pyobject import Py_DecRef, PyObject
+        Py_DecRef(space, rffi.cast(PyObject, rffi.cast(rffi.VOIDPP, arg)[0]))
+
+
+_converters = {}         # builtin and custom types
+_a_converters = {}       # array and ptr versions of above
+def get_converter(space, name, default):
+    # The matching of the name to a converter should follow:
+    #   1) full, exact match
+    #       1a) const-removed match
+    #   2) match of decorated, unqualified type
+    #   3) accept ref as pointer (for the stubs, const& can be
+    #       by value, but that does not work for the ffi path)
+    #   4) generalized cases (covers basically all user classes)
+    #   5) void converter, which fails on use
+
+    name = capi.c_resolve_name(name)
+
+    #   1) full, exact match
+    try:
+        return _converters[name](space, default)
+    except KeyError:
+        pass
+
+    #   1a) const-removed match
+    try:
+        return _converters[helper.remove_const(name)](space, default)
+    except KeyError:
+        pass
+
+    #   2) match of decorated, unqualified type
+    compound = helper.compound(name)
+    clean_name = helper.clean_type(name)
+    try:
+        # array_index may be negative to indicate no size or no size found
+        array_size = helper.array_size(name)
+        return _a_converters[clean_name+compound](space, array_size)
+    except KeyError:
+        pass
+
+    #   3) TODO: accept ref as pointer
+
+    #   4) generalized cases (covers basically all user classes)
+    from pypy.module.cppyy import interp_cppyy
+    cppclass = interp_cppyy.scope_byname(space, clean_name)
+    if cppclass:
+        # type check for the benefit of the annotator
+        from pypy.module.cppyy.interp_cppyy import W_CPPClass
+        cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
+        if compound == "*" or compound == "&":
+            return InstancePtrConverter(space, cppclass)
+        elif compound == "**":
+            return InstancePtrPtrConverter(space, cppclass)
+        elif compound == "":
+            return InstanceConverter(space, cppclass)
+    elif capi.c_is_enum(clean_name):
+        return UnsignedIntConverter(space, default)
+    
+    #   5) void converter, which fails on use
+    #
+    # return a void converter here, so that the class can be build even
+    # when some types are unknown; this overload will simply fail on use
+    return VoidConverter(space, name)
+
+
+_converters["bool"]                     = BoolConverter
+_converters["char"]                     = CharConverter
+_converters["unsigned char"]            = CharConverter
+_converters["short int"]                = ShortConverter
+_converters["const short int&"]         = ConstShortRefConverter
+_converters["short"]                    = _converters["short int"]
+_converters["const short&"]             = _converters["const short int&"]
+_converters["unsigned short int"]       = UnsignedShortConverter
+_converters["const unsigned short int&"] = ConstUnsignedShortRefConverter
+_converters["unsigned short"]           = _converters["unsigned short int"]
+_converters["const unsigned short&"]    = _converters["const unsigned short int&"]
+_converters["int"]                      = IntConverter
+_converters["const int&"]               = ConstIntRefConverter
+_converters["unsigned int"]             = UnsignedIntConverter
+_converters["const unsigned int&"]      = ConstUnsignedIntRefConverter
+_converters["long int"]                 = LongConverter
+_converters["const long int&"]          = ConstLongRefConverter
+_converters["long"]                     = _converters["long int"]
+_converters["const long&"]              = _converters["const long int&"]
+_converters["unsigned long int"]        = UnsignedLongConverter
+_converters["const unsigned long int&"] = ConstUnsignedLongRefConverter
+_converters["unsigned long"]            = _converters["unsigned long int"]
+_converters["const unsigned long&"]     = _converters["const unsigned long int&"]
+_converters["long long int"]            = LongLongConverter
+_converters["const long long int&"]     = ConstLongLongRefConverter
+_converters["long long"]                = _converters["long long int"]
+_converters["const long long&"]         = _converters["const long long int&"]
+_converters["unsigned long long int"]   = UnsignedLongLongConverter
+_converters["const unsigned long long int&"] = ConstUnsignedLongLongRefConverter
+_converters["unsigned long long"]       = _converters["unsigned long long int"]
+_converters["const unsigned long long&"] = _converters["const unsigned long long int&"]
+_converters["float"]                    = FloatConverter
+_converters["const float&"]             = ConstFloatRefConverter
+_converters["double"]                   = DoubleConverter
+_converters["const double&"]            = ConstDoubleRefConverter
+_converters["const char*"]              = CStringConverter
+_converters["char*"]                    = CStringConverter
+_converters["void*"]                    = VoidPtrConverter
+_converters["void**"]                   = VoidPtrPtrConverter
+_converters["void*&"]                   = VoidPtrRefConverter
+
+# special cases (note: CINT backend requires the simple name 'string')
+_converters["std::basic_string<char>"]           = StdStringConverter
+_converters["string"]                            = _converters["std::basic_string<char>"]
+_converters["const std::basic_string<char>&"]    = StdStringConverter     # TODO: shouldn't copy
+_converters["const string&"]                     = _converters["const std::basic_string<char>&"]
+_converters["std::basic_string<char>&"]          = StdStringRefConverter
+_converters["string&"]                           = _converters["std::basic_string<char>&"]
+
+_converters["PyObject*"]                         = PyObjectConverter
+_converters["_object*"]                          = _converters["PyObject*"]
+
+def _build_array_converters():
+    "NOT_RPYTHON"
+    array_info = (
+        ('h', rffi.sizeof(rffi.SHORT),  ("short int", "short")),
+        ('H', rffi.sizeof(rffi.USHORT), ("unsigned short int", "unsigned short")),
+        ('i', rffi.sizeof(rffi.INT),    ("int",)),
+        ('I', rffi.sizeof(rffi.UINT),   ("unsigned int", "unsigned")),
+        ('l', rffi.sizeof(rffi.LONG),   ("long int", "long")),
+        ('L', rffi.sizeof(rffi.ULONG),  ("unsigned long int", "unsigned long")),
+        ('f', rffi.sizeof(rffi.FLOAT),  ("float",)),
+        ('d', rffi.sizeof(rffi.DOUBLE), ("double",)),
+    )
+
+    for info in array_info:
+        class ArrayConverter(ArrayTypeConverterMixin, TypeConverter):
+            _immutable_ = True
+            typecode = info[0]
+            typesize = info[1]
+        class PtrConverter(PtrTypeConverterMixin, TypeConverter):
+            _immutable_ = True
+            typecode = info[0]
+            typesize = info[1]
+        for name in info[2]:
+            _a_converters[name+'[]'] = ArrayConverter
+            _a_converters[name+'*']  = PtrConverter
+_build_array_converters()
diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/executor.py
@@ -0,0 +1,466 @@
+import sys
+
+from pypy.interpreter.error import OperationError
+
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib import libffi, clibffi
+
+from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+from pypy.module._rawffi.array import W_Array
+
+from pypy.module.cppyy import helper, capi
+
+
+NULL = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+
+class FunctionExecutor(object):
+    _immutable_ = True
+    libffitype = NULL
+
+    def __init__(self, space, extra):
+        pass
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        raise OperationError(space.w_TypeError,
+                             space.wrap('return type not available or supported'))
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+
+class PtrTypeExecutor(FunctionExecutor):
+    _immutable_ = True
+    typecode = 'P'
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
+        address = rffi.cast(rffi.ULONG, lresult)
+        arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap(self.typecode)))
+        return arr.fromaddress(space, address, sys.maxint)
+
+
+class VoidExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = 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)
+        return space.w_None
+
+
+class BoolExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.schar
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_b(cppmethod, cppthis, num_args, args)
+        return space.wrap(result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.CHAR)
+        return space.wrap(bool(ord(result)))
+
+class CharExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.schar
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_c(cppmethod, cppthis, num_args, args)
+        return space.wrap(result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.CHAR)
+        return space.wrap(result)
+
+class ShortExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.sshort
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_h(cppmethod, cppthis, num_args, args)
+        return space.wrap(result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.SHORT)
+        return space.wrap(result)
+
+class IntExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.sint
+
+    def _wrap_result(self, space, result):
+        return space.wrap(result)
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_i(cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.INT)
+        return space.wrap(result)
+
+class UnsignedIntExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.uint
+
+    def _wrap_result(self, space, result):
+        return space.wrap(rffi.cast(rffi.UINT, result))
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_l(cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.UINT)
+        return space.wrap(result)
+
+class LongExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.slong
+
+    def _wrap_result(self, space, result):
+        return space.wrap(result)
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_l(cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.LONG)
+        return space.wrap(result)
+
+class UnsignedLongExecutor(LongExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.ulong
+
+    def _wrap_result(self, space, result):
+        return space.wrap(rffi.cast(rffi.ULONG, result))
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.ULONG)
+        return space.wrap(result)
+
+class LongLongExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.sint64
+
+    def _wrap_result(self, space, result):
+        return space.wrap(result)
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_ll(cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.LONGLONG)
+        return space.wrap(result)
+
+class UnsignedLongLongExecutor(LongLongExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.uint64
+
+    def _wrap_result(self, space, result):
+        return space.wrap(rffi.cast(rffi.ULONGLONG, result))
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.ULONGLONG)
+        return space.wrap(result)
+
+class ConstIntRefExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+    def _wrap_result(self, space, result):
+        intptr = rffi.cast(rffi.INTP, result)
+        return space.wrap(intptr[0])
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_r(cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.INTP)
+        return space.wrap(result[0])
+
+class ConstLongRefExecutor(ConstIntRefExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+    def _wrap_result(self, space, result):
+        longptr = rffi.cast(rffi.LONGP, result)
+        return space.wrap(longptr[0])
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.LONGP)
+        return space.wrap(result[0])
+
+class FloatExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.float
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_f(cppmethod, cppthis, num_args, args)
+        return space.wrap(float(result))
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.FLOAT)
+        return space.wrap(float(result))
+
+class DoubleExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.double
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_d(cppmethod, cppthis, num_args, args)
+        return space.wrap(result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.DOUBLE)
+        return space.wrap(result)
+
+
+class CStringExecutor(FunctionExecutor):
+    _immutable_ = True
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
+        ccpresult = rffi.cast(rffi.CCHARP, lresult)
+        result = rffi.charp2str(ccpresult)  # TODO: make it a choice to free
+        return space.wrap(result)
+
+
+class ShortPtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'h'
+
+class IntPtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'i'
+
+class UnsignedIntPtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'I'
+
+class LongPtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'l'
+
+class UnsignedLongPtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'L'
+
+class FloatPtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'f'
+
+class DoublePtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'd'
+
+
+class ConstructorExecutor(VoidExecutor):
+    _immutable_ = True
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        capi.c_constructor(cppmethod, cppthis, num_args, args)
+        return space.w_None
+
+
+class InstancePtrExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+    def __init__(self, space, cppclass):
+        FunctionExecutor.__init__(self, space, cppclass)
+        self.cppclass = cppclass
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        from pypy.module.cppyy import interp_cppyy
+        long_result = capi.c_call_l(cppmethod, cppthis, num_args, args)
+        ptr_result = rffi.cast(capi.C_OBJECT, long_result)
+        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):
+        from pypy.module.cppyy import interp_cppyy
+        ptr_result = rffi.cast(capi.C_OBJECT, libffifunc.call(argchain, rffi.VOIDP))
+        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
+        voidp_result = capi.c_call_r(cppmethod, cppthis, num_args, args)
+        ref_address = rffi.cast(rffi.VOIDPP, voidp_result)
+        ptr_result = rffi.cast(capi.C_OBJECT, ref_address[0])
+        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):
+        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
+        long_result = capi.c_call_o(cppmethod, cppthis, num_args, args, self.cppclass)
+        ptr_result = rffi.cast(capi.C_OBJECT, long_result)
+        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):
+        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):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+
+class PyObjectExecutor(PtrTypeExecutor):
+    _immutable_ = True
+
+    def wrap_result(self, space, lresult):
+        space.getbuiltinmodule("cpyext")
+        from pypy.module.cpyext.pyobject import PyObject, from_ref, make_ref, Py_DecRef
+        result = rffi.cast(PyObject, lresult)
+        w_obj = from_ref(space, result)
+        if result:
+            Py_DecRef(space, result)
+        return w_obj
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
+        return self.wrap_result(space, lresult)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        lresult = libffifunc.call(argchain, rffi.LONG)
+        return self.wrap_result(space, lresult)
+
+
+_executors = {}
+def get_executor(space, name):
+    # Matching of 'name' to an executor factory goes through up to four levels:
+    #   1) full, qualified match
+    #   2) drop '&': by-ref is pretty much the same as by-value, python-wise
+    #   3) types/classes, either by ref/ptr or by value
+    #   4) additional special cases
+    #
+    # If all fails, a default is used, which can be ignored at least until use.
+
+    name = capi.c_resolve_name(name)
+
+    #   1) full, qualified match
+    try:
+        return _executors[name](space, None)
+    except KeyError:
+        pass
+
+    compound = helper.compound(name)
+    clean_name = helper.clean_type(name)
+
+    #   1a) clean lookup
+    try:
+        return _executors[clean_name+compound](space, None)
+    except KeyError:
+        pass
+
+    #   2) drop '&': by-ref is pretty much the same as by-value, python-wise
+    if compound and compound[len(compound)-1] == "&":
+        # TODO: this does not actually work with Reflex (?)
+        try:
+            return _executors[clean_name](space, None)
+        except KeyError:
+            pass
+
+    #   3) types/classes, either by ref/ptr or by value
+    from pypy.module.cppyy import interp_cppyy
+    cppclass = interp_cppyy.scope_byname(space, clean_name)
+    if cppclass:
+        # type check for the benefit of the annotator
+        from pypy.module.cppyy.interp_cppyy import W_CPPClass
+        cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
+        if compound == "":
+            return InstanceExecutor(space, cppclass)
+        elif compound == "*" or compound == "&":
+            return InstancePtrExecutor(space, cppclass)
+        elif compound == "**" or compound == "*&":
+            return InstancePtrPtrExecutor(space, cppclass)
+    elif capi.c_is_enum(clean_name):
+        return UnsignedIntExecutor(space, None)
+
+    # 4) additional special cases
+    # ... none for now
+
+    # currently used until proper lazy instantiation available in interp_cppyy
+    return FunctionExecutor(space, None)
+ 
+
+_executors["void"]                = VoidExecutor
+_executors["void*"]               = PtrTypeExecutor
+_executors["bool"]                = BoolExecutor
+_executors["char"]                = CharExecutor
+_executors["char*"]               = CStringExecutor
+_executors["unsigned char"]       = CharExecutor
+_executors["short int"]           = ShortExecutor
+_executors["short"]               = _executors["short int"]
+_executors["short int*"]          = ShortPtrExecutor
+_executors["short*"]              = _executors["short int*"]
+_executors["unsigned short int"]  = ShortExecutor
+_executors["unsigned short"]      = _executors["unsigned short int"]
+_executors["unsigned short int*"] = ShortPtrExecutor
+_executors["unsigned short*"]     = _executors["unsigned short int*"]
+_executors["int"]                 = IntExecutor
+_executors["int*"]                = IntPtrExecutor
+_executors["const int&"]          = ConstIntRefExecutor
+_executors["int&"]                = ConstIntRefExecutor
+_executors["unsigned int"]        = UnsignedIntExecutor
+_executors["unsigned int*"]       = UnsignedIntPtrExecutor
+_executors["long int"]            = LongExecutor
+_executors["long"]                = _executors["long int"]
+_executors["long int*"]           = LongPtrExecutor
+_executors["long*"]               = _executors["long int*"]
+_executors["unsigned long int"]   = UnsignedLongExecutor
+_executors["unsigned long"]       = _executors["unsigned long int"]
+_executors["unsigned long int*"]  = UnsignedLongPtrExecutor
+_executors["unsigned long*"]      = _executors["unsigned long int*"]
+_executors["long long int"]       = LongLongExecutor
+_executors["long long"]           = _executors["long long int"]
+_executors["unsigned long long int"] = UnsignedLongLongExecutor
+_executors["unsigned long long"]  = _executors["unsigned long long int"]
+_executors["float"]               = FloatExecutor
+_executors["float*"]              = FloatPtrExecutor
+_executors["double"]              = DoubleExecutor
+_executors["double*"]             = DoublePtrExecutor
+
+_executors["constructor"]         = ConstructorExecutor
+
+# special cases (note: CINT backend requires the simple name 'string')
+_executors["std::basic_string<char>"]        = StdStringExecutor
+_executors["string"]                         = _executors["std::basic_string<char>"]
+
+_executors["PyObject*"]           = PyObjectExecutor
+_executors["_object*"]            = _executors["PyObject*"]
diff --git a/pypy/module/cppyy/genreflex-methptrgetter.patch b/pypy/module/cppyy/genreflex-methptrgetter.patch
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/genreflex-methptrgetter.patch
@@ -0,0 +1,126 @@
+Index: cint/reflex/python/genreflex/gendict.py
+===================================================================
+--- cint/reflex/python/genreflex/gendict.py	(revision 43705)
++++ cint/reflex/python/genreflex/gendict.py	(working copy)
+@@ -52,6 +52,7 @@
+     self.typedefs_for_usr = []
+     self.gccxmlvers = gccxmlvers
+     self.split = opts.get('split', '')
++    self.with_methptrgetter = opts.get('with_methptrgetter', False)
+     # The next is to avoid a known problem with gccxml that it generates a
+     # references to id equal '_0' which is not defined anywhere
+     self.xref['_0'] = {'elem':'Unknown', 'attrs':{'id':'_0','name':''}, 'subelems':[]}
+@@ -1306,6 +1307,8 @@
+     bases = self.getBases( attrs['id'] )
+     if inner and attrs.has_key('demangled') and self.isUnnamedType(attrs['demangled']) :
+       cls = attrs['demangled']
++      if self.xref[attrs['id']]['elem'] == 'Union':
++         return 80*' '
+       clt = ''
+     else:
+       cls = self.genTypeName(attrs['id'],const=True,colon=True)
+@@ -1343,7 +1346,7 @@
+       # Inner class/struct/union/enum.
+       for m in memList :
+         member = self.xref[m]
+-        if member['elem'] in ('Class','Struct','Union','Enumeration') \
++        if member['elem'] in ('Class','Struct','Enumeration') \
+            and member['attrs'].get('access') in ('private','protected') \
+            and not self.isUnnamedType(member['attrs'].get('demangled')):
+           cmem = self.genTypeName(member['attrs']['id'],const=True,colon=True)
+@@ -1981,8 +1984,15 @@
+     else    : params  = '0'
+     s = '  .AddFunctionMember(%s, Reflex::Literal("%s"), %s%s, 0, %s, %s)' % (self.genTypeID(id), name, type, id, params, mod)
+     s += self.genCommentProperty(attrs)
++    s += self.genMethPtrGetterProperty(type, attrs)
+     return s
+ #----------------------------------------------------------------------------------
++  def genMethPtrGetterProperty(self, type, attrs):
++    funcname = self.nameOfMethPtrGetter(type, attrs)
++    if funcname is None:
++      return ''
++    return '\n  .AddProperty("MethPtrGetter", (void*)%s)' % funcname
++#----------------------------------------------------------------------------------
+   def genMCODef(self, type, name, attrs, args):
+     id       = attrs['id']
+     cl       = self.genTypeName(attrs['context'],colon=True)
+@@ -2049,8 +2059,44 @@
+           if returns == 'void' : body += '  }\n'
+           else :                 body += '  }\n'
+     body += '}\n'
+-    return head + body;
++    methptrgetter = self.genMethPtrGetter(type, name, attrs, args)
++    return head + body + methptrgetter
+ #----------------------------------------------------------------------------------
++  def nameOfMethPtrGetter(self, type, attrs):
++    id = attrs['id']
++    if self.with_methptrgetter and 'static' not in attrs and type in ('operator', 'method'):
++      return '%s%s_methptrgetter' % (type, id)
++    return None
++#----------------------------------------------------------------------------------  
++  def genMethPtrGetter(self, type, name, attrs, args):
++    funcname = self.nameOfMethPtrGetter(type, attrs)
++    if funcname is None:
++      return ''
++    id = attrs['id']
++    cl = self.genTypeName(attrs['context'],colon=True)
++    rettype = self.genTypeName(attrs['returns'],enum=True, const=True, colon=True)
++    arg_type_list = [self.genTypeName(arg['type'], colon=True) for arg in args]
++    constness = attrs.get('const', 0) and 'const' or ''
++    lines = []
++    a = lines.append
++    a('static void* %s(void* o)' % (funcname,))
++    a('{')
++    if name == 'EmitVA':
++      # TODO: this is for ROOT TQObject, the problem being that ellipses is not
++      # exposed in the arguments and that makes the generated code fail if the named
++      # method is overloaded as is with TQObject::EmitVA
++      a('  return (void*)0;')
++    else:
++      # declare a variable "meth" which is a member pointer
++      a('  %s (%s::*meth)(%s)%s;' % (rettype, cl, ', '.join(arg_type_list), constness))
++      a('  meth = (%s (%s::*)(%s)%s)&%s::%s;' % \
++         (rettype, cl, ', '.join(arg_type_list), constness, cl, name))
++      a('  %s* obj = (%s*)o;' % (cl, cl))
++      a('  return (void*)(obj->*meth);')
++    a('}')
++    return '\n'.join(lines)
++
++#----------------------------------------------------------------------------------
+   def getDefaultArgs(self, args):
+     n = 0
+     for a in args :
+Index: cint/reflex/python/genreflex/genreflex.py
+===================================================================
+--- cint/reflex/python/genreflex/genreflex.py	(revision 43705)
++++ cint/reflex/python/genreflex/genreflex.py	(working copy)
+@@ -108,6 +108,10 @@
+          Print extra debug information while processing. Keep intermediate files\n
+       --quiet
+          Do not print informational messages\n
++      --with-methptrgetter
++         Add the property MethPtrGetter to every FunctionMember. It contains a pointer to a
++         function which you can call to get the actual function pointer of the method that it's
++         stored in the vtable.  It works only with gcc.
+       -h, --help
+          Print this help\n
+      """ 
+@@ -127,7 +131,8 @@
+       opts, args = getopt.getopt(options, 'ho:s:c:I:U:D:PC', \
+       ['help','debug=', 'output=','selection_file=','pool','dataonly','interpreteronly','deep','gccxmlpath=',
+        'capabilities=','rootmap=','rootmap-lib=','comments','iocomments','no_membertypedefs',
+-       'fail_on_warnings', 'quiet', 'gccxmlopt=', 'reflex', 'split=','no_templatetypedefs','gccxmlpost='])
++       'fail_on_warnings', 'quiet', 'gccxmlopt=', 'reflex', 'split=','no_templatetypedefs','gccxmlpost=',
++       'with-methptrgetter'])
+     except getopt.GetoptError, e:
+       print "--->> genreflex: ERROR:",e
+       self.usage(2)
+@@ -186,6 +191,8 @@
+         self.rootmap = a
+       if o in ('--rootmap-lib',):
+         self.rootmaplib = a
++      if o in ('--with-methptrgetter',):
++        self.opts['with_methptrgetter'] = True
+       if o in ('-I', '-U', '-D', '-P', '-C') :
+         # escape quotes; we need to use " because of windows cmd
+         poseq = a.find('=')
diff --git a/pypy/module/cppyy/helper.py b/pypy/module/cppyy/helper.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/helper.py
@@ -0,0 +1,179 @@
+from pypy.rlib import rstring
+
+
+#- type name manipulations --------------------------------------------------
+def _remove_const(name):
+    return "".join(rstring.split(name, "const")) # poor man's replace
+
+def remove_const(name):
+    return _remove_const(name).strip(' ')
+
+def compound(name):
+    name = _remove_const(name)
+    if name.endswith("]"):                       # array type?
+        return "[]"
+    i = _find_qualifier_index(name)
+    return "".join(name[i:].split(" "))
+
+def array_size(name):
+    name = _remove_const(name)
+    if name.endswith("]"):                       # array type?
+        idx = name.rfind("[")
+        if 0 < idx:
+            end = len(name)-1                    # len rather than -1 for rpython
+            if 0 < end and (idx+1) < end:        # guarantee non-neg for rpython
+                return int(name[idx+1:end])
+    return -1
+
+def _find_qualifier_index(name):
+    i = len(name)
+    # search from the back; note len(name) > 0 (so rtyper can use uint)
+    for i in range(len(name) - 1, 0, -1):
+        c = name[i]
+        if c.isalnum() or c == ">" or c == "]":
+            break
+    return i + 1
+
+def clean_type(name):
+    # can't strip const early b/c name could be a template ...
+    i = _find_qualifier_index(name)
+    name = name[:i].strip(' ')
+
+    idx = -1
+    if name.endswith("]"):                       # array type?
+        idx = name.rfind("[")
+        if 0 < idx:
+             name = name[:idx]
+    elif name.endswith(">"):                     # template type?
+        idx = name.find("<")
+        if 0 < idx:      # always true, but just so that the translater knows
+            n1 = _remove_const(name[:idx])
+            name = "".join([n1, name[idx:]])
+    else:
+        name = _remove_const(name)
+        name = name[:_find_qualifier_index(name)]
+    return name.strip(' ')
+
+
+#- operator mappings --------------------------------------------------------
+_operator_mappings = {}
+
+def map_operator_name(cppname, nargs, result_type):
+    from pypy.module.cppyy import capi
+
+    if cppname[0:8] == "operator":
+        op = cppname[8:].strip(' ')
+
+        # look for known mapping
+        try:
+            return _operator_mappings[op]
+        except KeyError:
+            pass
+
+        # return-type dependent mapping
+        if op == "[]":
+            if result_type.find("const") != 0:
+                cpd = compound(result_type)
+                if cpd and cpd[len(cpd)-1] == "&":
+                    return "__setitem__"
+            return "__getitem__"
+
+        # a couple more cases that depend on whether args were given
+
+        if op == "*":   # dereference (not python) vs. multiplication
+            return nargs and "__mul__" or "__deref__"
+
+        if op == "+":   # unary positive vs. binary addition
+            return nargs and  "__add__" or "__pos__"
+
+        if op == "-":   # unary negative vs. binary subtraction
+            return nargs and "__sub__" or "__neg__"
+
+        if op == "++":  # prefix v.s. postfix increment (not python)
+            return nargs and "__postinc__" or "__preinc__";
+
+        if op == "--":  # prefix v.s. postfix decrement (not python)
+            return nargs and "__postdec__" or "__predec__";
+
+        # operator could have been a conversion using a typedef (this lookup
+        # is put at the end only as it is unlikely and may trigger unwanted
+        # errors in class loaders in the backend, because a typical operator
+        # name is illegal as a class name)
+        true_op = capi.c_resolve_name(op)
+
+        try:
+            return _operator_mappings[true_op]
+        except KeyError:
+            pass
+
+    # might get here, as not all operator methods handled (although some with
+    # no python equivalent, such as new, delete, etc., are simply retained)
+    # TODO: perhaps absorb or "pythonify" these operators?
+    return cppname
+
+# _operator_mappings["[]"]  = "__setitem__"      # depends on return type
+# _operator_mappings["+"]   = "__add__"          # depends on # of args (see __pos__)
+# _operator_mappings["-"]   = "__sub__"          # id. (eq. __neg__)
+# _operator_mappings["*"]   = "__mul__"          # double meaning in C++
+
+# _operator_mappings["[]"]  = "__getitem__"      # depends on return type
+_operator_mappings["()"]  = "__call__"
+_operator_mappings["/"]   = "__div__"            # __truediv__ in p3
+_operator_mappings["%"]   = "__mod__"
+_operator_mappings["**"]  = "__pow__"            # not C++
+_operator_mappings["<<"]  = "__lshift__"
+_operator_mappings[">>"]  = "__rshift__"
+_operator_mappings["&"]   = "__and__"
+_operator_mappings["|"]   = "__or__"
+_operator_mappings["^"]   = "__xor__"
+_operator_mappings["~"]   = "__inv__"
+_operator_mappings["!"]   = "__nonzero__"
+_operator_mappings["+="]  = "__iadd__"
+_operator_mappings["-="]  = "__isub__"
+_operator_mappings["*="]  = "__imul__"
+_operator_mappings["/="]  = "__idiv__"           # __itruediv__ in p3
+_operator_mappings["%="]  = "__imod__"
+_operator_mappings["**="] = "__ipow__"
+_operator_mappings["<<="] = "__ilshift__"
+_operator_mappings[">>="] = "__irshift__"
+_operator_mappings["&="]  = "__iand__"
+_operator_mappings["|="]  = "__ior__"
+_operator_mappings["^="]  = "__ixor__"
+_operator_mappings["=="]  = "__eq__"
+_operator_mappings["!="]  = "__ne__"
+_operator_mappings[">"]   = "__gt__"
+_operator_mappings["<"]   = "__lt__"
+_operator_mappings[">="]  = "__ge__"
+_operator_mappings["<="]  = "__le__"
+
+# the following type mappings are "exact"
+_operator_mappings["const char*"] = "__str__"
+_operator_mappings["int"]         = "__int__"
+_operator_mappings["long"]        = "__long__"   # __int__ in p3
+_operator_mappings["double"]      = "__float__"
+
+# the following type mappings are "okay"; the assumption is that they
+# are not mixed up with the ones above or between themselves (and if
+# they are, that it is done consistently)
+_operator_mappings["char*"]              = "__str__"
+_operator_mappings["short"]              = "__int__"
+_operator_mappings["unsigned short"]     = "__int__"
+_operator_mappings["unsigned int"]       = "__long__"      # __int__ in p3
+_operator_mappings["unsigned long"]      = "__long__"      # id.
+_operator_mappings["long long"]          = "__long__"      # id.
+_operator_mappings["unsigned long long"] = "__long__"      # id.
+_operator_mappings["float"]              = "__float__"
+
+_operator_mappings["bool"] = "__nonzero__"       # __bool__ in p3
+
+# the following are not python, but useful to expose
+_operator_mappings["->"]  = "__follow__"
+_operator_mappings["="]   = "__assign__"
+
+# a bundle of operators that have no equivalent and are left "as-is" for now:
+_operator_mappings["&&"]       = "&&"
+_operator_mappings["||"]       = "||"
+_operator_mappings["new"]      = "new"
+_operator_mappings["delete"]   = "delete"
+_operator_mappings["new[]"]    = "new[]"
+_operator_mappings["delete[]"] = "delete[]"
diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/capi.h
@@ -0,0 +1,111 @@
+#ifndef CPPYY_CAPI
+#define CPPYY_CAPI
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif // ifdef __cplusplus
+
+    typedef long cppyy_scope_t;
+    typedef cppyy_scope_t cppyy_type_t;
+    typedef long cppyy_object_t;
+    typedef long cppyy_method_t;
+    typedef void* (*cppyy_methptrgetter_t)(cppyy_object_t);
+
+    /* name to opaque C++ scope representation -------------------------------- */
+    char* cppyy_resolve_name(const char* cppitem_name);
+    cppyy_scope_t cppyy_get_scope(const char* scope_name);
+    cppyy_type_t cppyy_get_template(const char* template_name);
+    cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj);
+
+    /* memory management ------------------------------------------------------ */
+    cppyy_object_t cppyy_allocate(cppyy_type_t type);
+    void cppyy_deallocate(cppyy_type_t type, cppyy_object_t self);
+    void cppyy_destruct(cppyy_type_t type, cppyy_object_t self);
+
+    /* method/function dispatching -------------------------------------------- */
+    void   cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    int    cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    char   cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    short  cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    int    cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    long   cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+
+    void*  cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    char*  cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+
+    void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, cppyy_type_t result_type);
+
+    cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_scope_t scope, int method_index);
+
+    /* handling of function argument buffer ----------------------------------- */
+    void*  cppyy_allocate_function_args(size_t nargs);
+    void   cppyy_deallocate_function_args(void* args);
+    size_t cppyy_function_arg_sizeof();
+    size_t cppyy_function_arg_typeoffset();
+
+    /* scope reflection information ------------------------------------------- */
+    int cppyy_is_namespace(cppyy_scope_t scope);
+    int cppyy_is_enum(const char* type_name);
+
+    /* class reflection information ------------------------------------------- */
+    char* cppyy_final_name(cppyy_type_t type);
+    char* cppyy_scoped_final_name(cppyy_type_t type);
+    int cppyy_has_complex_hierarchy(cppyy_type_t type);
+    int cppyy_num_bases(cppyy_type_t type);
+    char* cppyy_base_name(cppyy_type_t type, int base_index);
+    int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base);
+
+    /* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */
+    size_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction);
+
+    /* method/function reflection information --------------------------------- */
+    int cppyy_num_methods(cppyy_scope_t scope);
+    char* cppyy_method_name(cppyy_scope_t scope, int method_index);
+    char* cppyy_method_result_type(cppyy_scope_t scope, int method_index);
+    int cppyy_method_num_args(cppyy_scope_t scope, int method_index);
+    int cppyy_method_req_args(cppyy_scope_t scope, int method_index);
+    char* cppyy_method_arg_type(cppyy_scope_t scope, int method_index, int arg_index);
+    char* cppyy_method_arg_default(cppyy_scope_t scope, int method_index, int arg_index);
+    char* cppyy_method_signature(cppyy_scope_t scope, int method_index);
+
+    int cppyy_method_index(cppyy_scope_t scope, const char* name);
+
+    cppyy_method_t cppyy_get_method(cppyy_scope_t scope, int method_index);
+
+    /* method properties -----------------------------------------------------  */
+    int cppyy_is_constructor(cppyy_type_t type, int method_index);
+    int cppyy_is_staticmethod(cppyy_type_t type, int method_index);
+
+    /* data member reflection information ------------------------------------  */
+    int cppyy_num_datamembers(cppyy_scope_t scope);
+    char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index);
+    char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index);
+    size_t cppyy_datamember_offset(cppyy_scope_t scope, int datamember_index);
+
+    int cppyy_datamember_index(cppyy_scope_t scope, const char* name);
+
+    /* data member properties ------------------------------------------------  */
+    int cppyy_is_publicdata(cppyy_type_t type, int datamember_index);
+    int cppyy_is_staticdata(cppyy_type_t type, int datamember_index);
+
+    /* misc helpers ----------------------------------------------------------- */
+    void cppyy_free(void* ptr);
+    long long cppyy_strtoll(const char* str);
+    unsigned long long cppyy_strtuoll(const char* str);
+
+    cppyy_object_t cppyy_charp2stdstring(const char* str);
+    cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr);
+    void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str);
+    void cppyy_free_stdstring(cppyy_object_t ptr);
+
+#ifdef __cplusplus
+}
+#endif // ifdef __cplusplus
+
+#endif // ifndef CPPYY_CAPI
diff --git a/pypy/module/cppyy/include/cintcwrapper.h b/pypy/module/cppyy/include/cintcwrapper.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/cintcwrapper.h
@@ -0,0 +1,16 @@
+#ifndef CPPYY_CINTCWRAPPER
+#define CPPYY_CINTCWRAPPER
+
+#include "capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // ifdef __cplusplus
+
+    void* cppyy_load_dictionary(const char* lib_name);
+
+#ifdef __cplusplus
+}
+#endif // ifdef __cplusplus
+
+#endif // ifndef CPPYY_CINTCWRAPPER
diff --git a/pypy/module/cppyy/include/cppyy.h b/pypy/module/cppyy/include/cppyy.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/cppyy.h
@@ -0,0 +1,64 @@
+#ifndef CPPYY_CPPYY
+#define CPPYY_CPPYY
+
+#ifdef __cplusplus
+struct CPPYY_G__DUMMY_FOR_CINT7 {
+#else
+typedef struct
+#endif
+   void* fTypeName;
+   unsigned int fModifiers;
+#ifdef __cplusplus
+};
+#else
+} CPPYY_G__DUMMY_FOR_CINT7;
+#endif
+
+#ifdef __cplusplus
+struct CPPYY_G__p2p {
+#else
+#typedef struct
+#endif
+  long i;
+  int reftype;
+#ifdef __cplusplus
+};
+#else
+} CPPYY_G__p2p;
+#endif
+
+
+#ifdef __cplusplus
+struct CPPYY_G__value {
+#else
+typedef struct {
+#endif
+  union {
+    double d;
+    long    i; /* used to be int */
+    struct CPPYY_G__p2p reftype;
+    char ch;
+    short sh;
+    int in;
+    float fl;
+    unsigned char uch;
+    unsigned short ush;
+    unsigned int uin;
+    unsigned long ulo;
+    long long ll;
+    unsigned long long ull;
+    long double ld;
+  } obj;
+  long ref;
+  int type;
+  int tagnum;
+  int typenum;
+  char isconst;
+  struct CPPYY_G__DUMMY_FOR_CINT7 dummyForCint7;
+#ifdef __cplusplus
+};
+#else
+} CPPYY_G__value;
+#endif
+
+#endif // CPPYY_CPPYY
diff --git a/pypy/module/cppyy/include/reflexcwrapper.h b/pypy/module/cppyy/include/reflexcwrapper.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/reflexcwrapper.h
@@ -0,0 +1,6 @@
+#ifndef CPPYY_REFLEXCWRAPPER
+#define CPPYY_REFLEXCWRAPPER
+
+#include "capi.h"
+
+#endif // ifndef CPPYY_REFLEXCWRAPPER
diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -0,0 +1,807 @@
+import pypy.module.cppyy.capi as capi
+
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+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.rlib import libffi, rdynload, rweakref
+from pypy.rlib import jit, debug, objectmodel
+
+from pypy.module.cppyy import converter, executor, helper
+
+
+class FastCallNotPossible(Exception):
+    pass
+
+
+ at unwrap_spec(name=str)
+def load_dictionary(space, name):
+    try:
+        cdll = capi.c_load_dictionary(name)
+    except rdynload.DLOpenError, e:
+        raise OperationError(space.w_RuntimeError, space.wrap(str(e)))
+    return W_CPPLibrary(space, cdll)
+
+class State(object):
+    def __init__(self, space):
+        self.cppscope_cache = {
+            "void" : W_CPPClass(space, "void", capi.C_NULL_TYPE) }
+        self.cpptemplate_cache = {}
+        self.cppclass_registry = {}
+        self.w_clgen_callback = None
+
+ at unwrap_spec(name=str)
+def resolve_name(space, name):
+    return space.wrap(capi.c_resolve_name(name))
+
+ at unwrap_spec(name=str)
+def scope_byname(space, name):
+    true_name = capi.c_resolve_name(name)
+
+    state = space.fromcache(State)
+    try:
+        return state.cppscope_cache[true_name]
+    except KeyError:
+        pass
+
+    opaque_handle = capi.c_get_scope_opaque(true_name)
+    assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
+    if opaque_handle:
+        final_name = capi.c_final_name(opaque_handle)
+        if capi.c_is_namespace(opaque_handle):
+            cppscope = W_CPPNamespace(space, final_name, opaque_handle)
+        elif capi.c_has_complex_hierarchy(opaque_handle):
+            cppscope = W_ComplexCPPClass(space, final_name, opaque_handle)
+        else:
+            cppscope = W_CPPClass(space, final_name, opaque_handle)
+        state.cppscope_cache[name] = cppscope
+
+        cppscope._find_methods()
+        cppscope._find_datamembers()
+        return cppscope
+
+    return None
+
+ at unwrap_spec(name=str)
+def template_byname(space, name):
+    state = space.fromcache(State)
+    try:
+        return state.cpptemplate_cache[name]
+    except KeyError:
+        pass
+
+    opaque_handle = capi.c_get_template(name)
+    assert lltype.typeOf(opaque_handle) == capi.C_TYPE
+    if opaque_handle:
+        cpptemplate = W_CPPTemplateType(space, name, opaque_handle)
+        state.cpptemplate_cache[name] = cpptemplate
+        return cpptemplate
+
+    return None
+
+ at unwrap_spec(w_callback=W_Root)
+def set_class_generator(space, w_callback):
+    state = space.fromcache(State)
+    state.w_clgen_callback = w_callback
+
+ at unwrap_spec(w_pycppclass=W_Root)
+def register_class(space, w_pycppclass):
+    w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
+    cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+    state = space.fromcache(State)
+    state.cppclass_registry[cppclass.handle] = w_pycppclass
+
+
+class W_CPPLibrary(Wrappable):
+    _immutable_ = True
+
+    def __init__(self, space, cdll):
+        self.cdll = cdll
+        self.space = space
+
+W_CPPLibrary.typedef = TypeDef(
+    'CPPLibrary',
+)
+W_CPPLibrary.typedef.acceptable_as_base_class = True
+
+
+class CPPMethod(object):
+    """ A concrete function after overloading has been resolved """
+    _immutable_ = True
+    
+    def __init__(self, space, containing_scope, method_index, arg_defs, args_required):
+        self.space = space
+        self.scope = containing_scope
+        self.index = method_index
+        self.cppmethod = capi.c_get_method(self.scope, method_index)
+        self.arg_defs = arg_defs
+        self.args_required = args_required
+        self.args_expected = len(arg_defs)
+
+        # Setup of the method dispatch's innards is done lazily, i.e. only when
+        # the method is actually used.
+        self.converters = None
+        self.executor = None
+        self._libffifunc = None
+
+    def _address_from_local_buffer(self, call_local, idx):
+        if not call_local:
+            return call_local
+        stride = 2*rffi.sizeof(rffi.VOIDP)
+        loc_idx = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, call_local), idx*stride)
+        return rffi.cast(rffi.VOIDP, loc_idx)
+
+    @jit.unroll_safe
+    def call(self, cppthis, args_w):
+        jit.promote(self)
+        assert lltype.typeOf(cppthis) == capi.C_OBJECT
+
+        # check number of given arguments against required (== total - defaults)
+        args_expected = len(self.arg_defs)
+        args_given = len(args_w)
+        if args_expected < args_given or args_given < self.args_required:
+            raise OperationError(self.space.w_TypeError,
+                                 self.space.wrap("wrong number of arguments"))
+
+        # initial setup of converters, executors, and libffi (if available)
+        if self.converters is None:
+            self._setup(cppthis)
+
+        # some calls, e.g. for ptr-ptr or reference need a local array to store data for
+        # the duration of the call
+        if [conv for conv in self.converters if conv.uses_local]:
+            call_local = 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:
+                try:
+                    return self.do_fast_call(cppthis, args_w, call_local)
+                except FastCallNotPossible:
+                    pass      # can happen if converters or executor does not implement ffi
+
+            # ffi chain must have failed; using stub functions instead
+            args = self.prepare_arguments(args_w, call_local)
+            try:
+                return self.executor.execute(self.space, self.cppmethod, cppthis, len(args_w), args)
+            finally:
+                self.finalize_call(args, args_w, call_local)
+        finally:
+            if call_local:
+                lltype.free(call_local, flavor='raw')
+
+    @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)
+
+    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))
+
+        # 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
+
+    @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)):
+            conv = self.converters[i]
+            w_arg = args_w[i]
+            try:
+                arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
+                loc_i = self._address_from_local_buffer(call_local, i)
+                conv.convert_argument(self.space, w_arg, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
+            except:
+                # fun :-(
+                for j in range(i):
+                    conv = self.converters[j]
+                    arg_j = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), j*stride)
+                    loc_j = self._address_from_local_buffer(call_local, j)
+                    conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_j), loc_j)
+                capi.c_deallocate_function_args(args)
+                raise
+        return args
+
+    @jit.unroll_safe
+    def finalize_call(self, args, args_w, call_local):
+        stride = capi.c_function_arg_sizeof()
+        for i in range(len(args_w)):
+            conv = self.converters[i]
+            arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
+            loc_i = self._address_from_local_buffer(call_local, i)
+            conv.finalize_call(self.space, args_w[i], loc_i)
+            conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
+        capi.c_deallocate_function_args(args)
+
+    def signature(self):
+        return capi.c_method_signature(self.scope, self.index)
+
+    def __repr__(self):
+        return "CPPMethod: %s" % self.signature()
+
+    def _freeze_(self):
+        assert 0, "you should never have a pre-built instance of this!"
+
+
+class CPPFunction(CPPMethod):
+    _immutable_ = True
+
+    def __repr__(self):
+        return "CPPFunction: %s" % self.signature()
+
+
+class CPPConstructor(CPPMethod):
+    _immutable_ = True
+
+    def call(self, cppthis, args_w):
+        newthis = capi.c_allocate(self.scope)
+        assert lltype.typeOf(newthis) == capi.C_OBJECT
+        try:
+            CPPMethod.call(self, newthis, args_w)
+        except:
+            capi.c_deallocate(self.scope, newthis)
+            raise
+        return wrap_new_cppobject_nocast(
+            self.space, self.space.w_None, self.scope, newthis, isref=False, python_owns=True)
+
+    def __repr__(self):
+        return "CPPConstructor: %s" % self.signature()
+
+
+class W_CPPOverload(Wrappable):
+    _immutable_ = True
+
+    def __init__(self, space, containing_scope, functions):
+        self.space = space
+        self.scope = containing_scope
+        self.functions = debug.make_sure_not_resized(functions)
+
+    def is_static(self):
+        return self.space.wrap(isinstance(self.functions[0], CPPFunction))
+
+    @jit.unroll_safe
+    @unwrap_spec(args_w='args_w')
+    def call(self, w_cppinstance, args_w):
+        cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+        if cppinstance is not None:
+            cppinstance._nullcheck()
+            cppthis = cppinstance.get_cppthis(self.scope)
+        else:
+            cppthis = capi.C_NULL_OBJECT
+        assert lltype.typeOf(cppthis) == capi.C_OBJECT
+
+        # The following code tries out each of the functions in order. If
+        # argument conversion fails (or simply if the number of arguments do
+        # not match, that will lead to an exception, The JIT will snip out
+        # those (always) failing paths, but only if they have no side-effects.
+        # A second loop gathers all exceptions in the case all methods fail
+        # (the exception gathering would otherwise be a side-effect as far as
+        # the JIT is concerned).
+        #
+        # TODO: figure out what happens if a callback into from the C++ call
+        # raises a Python exception.
+        jit.promote(self)
+        for i in range(len(self.functions)):
+            cppyyfunc = self.functions[i]
+            try:
+                return cppyyfunc.call(cppthis, args_w)
+            except Exception:
+                pass
+
+        # only get here if all overloads failed ...
+        errmsg = 'none of the %d overloaded methods succeeded. Full details:' % len(self.functions)
+        if hasattr(self.space, "fake"):     # FakeSpace fails errorstr (see below)
+            raise OperationError(self.space.w_TypeError, self.space.wrap(errmsg))
+        for i in range(len(self.functions)):
+            cppyyfunc = self.functions[i]
+            try:
+                return cppyyfunc.call(cppthis, args_w)
+            except OperationError, e:
+                errmsg += '\n  '+cppyyfunc.signature()+' =>\n'
+                errmsg += '    '+e.errorstr(self.space)
+            except Exception, e:
+                errmsg += '\n  '+cppyyfunc.signature()+' =>\n'
+                errmsg += '    Exception: '+str(e)
+
+        raise OperationError(self.space.w_TypeError, self.space.wrap(errmsg))
+
+    def signature(self):
+        sig = self.functions[0].signature()
+        for i in range(1, len(self.functions)):
+            sig += '\n'+self.functions[i].signature()
+        return self.space.wrap(sig)
+
+    def __repr__(self):
+        return "W_CPPOverload(%s)" % [f.signature() for f in self.functions]
+
+W_CPPOverload.typedef = TypeDef(
+    'CPPOverload',
+    is_static = interp2app(W_CPPOverload.is_static),
+    call = interp2app(W_CPPOverload.call),
+    signature = interp2app(W_CPPOverload.signature),
+)
+
+
+class W_CPPDataMember(Wrappable):
+    _immutable_ = True
+
+    def __init__(self, space, containing_scope, type_name, offset, is_static):
+        self.space = space
+        self.scope = containing_scope
+        self.converter = converter.get_converter(self.space, type_name, '')
+        self.offset = offset
+        self._is_static = is_static
+
+    def get_returntype(self):
+        return self.space.wrap(self.converter.name)
+
+    def is_static(self):
+        return self.space.newbool(self._is_static)
+
+    @jit.elidable_promote()
+    def _get_offset(self, cppinstance):
+        if cppinstance:
+            assert lltype.typeOf(cppinstance.cppclass.handle) == lltype.typeOf(self.scope.handle)
+            offset = self.offset + capi.c_base_offset(
+                cppinstance.cppclass, self.scope, cppinstance.get_rawobject(), 1)
+        else:
+            offset = self.offset
+        return offset
+
+    def get(self, w_cppinstance, w_pycppclass):
+        cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+        offset = self._get_offset(cppinstance)
+        return self.converter.from_memory(self.space, w_cppinstance, w_pycppclass, offset)
+
+    def set(self, w_cppinstance, w_value):
+        cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+        offset = self._get_offset(cppinstance)
+        self.converter.to_memory(self.space, w_cppinstance, w_value, offset)
+        return self.space.w_None
+
+W_CPPDataMember.typedef = TypeDef(
+    'CPPDataMember',
+    is_static = interp2app(W_CPPDataMember.is_static),
+    get_returntype = interp2app(W_CPPDataMember.get_returntype),
+    get = interp2app(W_CPPDataMember.get),
+    set = interp2app(W_CPPDataMember.set),
+)
+W_CPPDataMember.typedef.acceptable_as_base_class = False
+
+
+class W_CPPScope(Wrappable):
+    _immutable_ = True
+    _immutable_fields_ = ["methods[*]", "datamembers[*]"]
+
+    kind = "scope"
+
+    def __init__(self, space, name, opaque_handle):
+        self.space = space
+        self.name = name
+        assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
+        self.handle = opaque_handle
+        self.methods = {}
+        # Do not call "self._find_methods()" here, so that a distinction can
+        #  be made between testing for existence (i.e. existence in the cache
+        #  of classes) and actual use. Point being that a class can use itself,
+        #  e.g. as a return type or an argument to one of its methods.
+
+        self.datamembers = {}
+        # Idem self.methods: a type could hold itself by pointer.
+
+    def _find_methods(self):
+        num_methods = capi.c_num_methods(self)
+        args_temp = {}
+        for i in range(num_methods):
+            method_name = capi.c_method_name(self, i)
+            pymethod_name = helper.map_operator_name(
+                    method_name, capi.c_method_num_args(self, i),
+                    capi.c_method_result_type(self, i))
+            if not pymethod_name in self.methods:
+                cppfunction = self._make_cppfunction(i)
+                overload = args_temp.setdefault(pymethod_name, [])
+                overload.append(cppfunction)
+        for name, functions in args_temp.iteritems():
+            overload = W_CPPOverload(self.space, self, functions[:])
+            self.methods[name] = overload
+
+    def get_method_names(self):
+        return self.space.newlist([self.space.wrap(name) for name in self.methods])
+
+    @jit.elidable_promote('0')
+    def get_overload(self, name):
+        try:
+            return self.methods[name]
+        except KeyError:
+            pass
+        new_method = self.find_overload(name)
+        self.methods[name] = new_method
+        return new_method
+
+    def get_datamember_names(self):
+        return self.space.newlist([self.space.wrap(name) for name in self.datamembers])
+
+    @jit.elidable_promote('0')
+    def get_datamember(self, name):
+        try:
+            return self.datamembers[name]
+        except KeyError:
+            pass
+        new_dm = self.find_datamember(name)
+        self.datamembers[name] = new_dm
+        return new_dm
+
+    @jit.elidable_promote('0')
+    def dispatch(self, name, signature):
+        overload = self.get_overload(name)
+        sig = '(%s)' % signature
+        for f in overload.functions:
+            if 0 < f.signature().find(sig):
+                return W_CPPOverload(self.space, self, [f])
+        raise OperationError(self.space.w_TypeError, self.space.wrap("no overload matches signature"))
+
+    def missing_attribute_error(self, name):
+        return OperationError(
+            self.space.w_AttributeError,
+            self.space.wrap("%s '%s' has no attribute %s" % (self.kind, self.name, name)))
+
+    def __eq__(self, other):
+        return self.handle == other.handle
+
+
+# For now, keep namespaces and classes separate as namespaces are extensible
+# with info from multiple dictionaries and do not need to bother with meta
+# classes for inheritance. Both are python classes, though, and refactoring
+# may be in order at some point.
+class W_CPPNamespace(W_CPPScope):
+    _immutable_ = True
+    kind = "namespace"
+
+    def _make_cppfunction(self, method_index):
+        num_args = capi.c_method_num_args(self, method_index)
+        args_required = capi.c_method_req_args(self, method_index)
+        arg_defs = []
+        for i in range(num_args):
+            arg_type = capi.c_method_arg_type(self, method_index, i)
+            arg_dflt = capi.c_method_arg_default(self, method_index, i)
+            arg_defs.append((arg_type, arg_dflt))
+        return CPPFunction(self.space, self, method_index, arg_defs, args_required)
+
+    def _make_datamember(self, dm_name, dm_idx):
+        type_name = capi.c_datamember_type(self, dm_idx)
+        offset = capi.c_datamember_offset(self, dm_idx)
+        datamember = W_CPPDataMember(self.space, self, type_name, offset, True)
+        self.datamembers[dm_name] = datamember
+        return datamember
+
+    def _find_datamembers(self):
+        num_datamembers = capi.c_num_datamembers(self)
+        for i in range(num_datamembers):
+            if not capi.c_is_publicdata(self, i):
+                continue
+            datamember_name = capi.c_datamember_name(self, i)
+            if not datamember_name in self.datamembers:
+                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(self, meth_name)
+        if meth_idx < 0:
+            raise self.missing_attribute_error(meth_name)
+        cppfunction = self._make_cppfunction(meth_idx)
+        overload = W_CPPOverload(self.space, self, [cppfunction])
+        return overload
+
+    def find_datamember(self, dm_name):
+        dm_idx = capi.c_datamember_index(self, dm_name)
+        if dm_idx < 0:
+            raise self.missing_attribute_error(dm_name)
+        datamember = self._make_datamember(dm_name, dm_idx)
+        return datamember
+
+    def update(self):
+        self._find_methods()
+        self._find_datamembers()
+
+    def is_namespace(self):
+        return self.space.w_True
+
+W_CPPNamespace.typedef = TypeDef(
+    'CPPNamespace',
+    update = interp2app(W_CPPNamespace.update),
+    get_method_names = interp2app(W_CPPNamespace.get_method_names),
+    get_overload = interp2app(W_CPPNamespace.get_overload, unwrap_spec=['self', str]),
+    get_datamember_names = interp2app(W_CPPNamespace.get_datamember_names),
+    get_datamember = interp2app(W_CPPNamespace.get_datamember, unwrap_spec=['self', str]),
+    is_namespace = interp2app(W_CPPNamespace.is_namespace),
+)
+W_CPPNamespace.typedef.acceptable_as_base_class = False
+
+
+class W_CPPClass(W_CPPScope):
+    _immutable_ = True
+    kind = "class"
+
+    def _make_cppfunction(self, method_index):
+        num_args = capi.c_method_num_args(self, method_index)
+        args_required = capi.c_method_req_args(self, method_index)
+        arg_defs = []
+        for i in range(num_args):
+            arg_type = capi.c_method_arg_type(self, method_index, i)
+            arg_dflt = capi.c_method_arg_default(self, method_index, i)
+            arg_defs.append((arg_type, arg_dflt))
+        if capi.c_is_constructor(self, method_index):
+            cls = CPPConstructor
+        elif capi.c_is_staticmethod(self, method_index):
+            cls = CPPFunction
+        else:
+            cls = CPPMethod
+        return cls(self.space, self, method_index, arg_defs, args_required)
+
+    def _find_datamembers(self):
+        num_datamembers = capi.c_num_datamembers(self)
+        for i in range(num_datamembers):
+            if not capi.c_is_publicdata(self, i):
+                continue
+            datamember_name = capi.c_datamember_name(self, i)
+            type_name = capi.c_datamember_type(self, i)
+            offset = capi.c_datamember_offset(self, i)
+            is_static = bool(capi.c_is_staticdata(self, i))
+            datamember = W_CPPDataMember(self.space, self, type_name, offset, is_static)
+            self.datamembers[datamember_name] = datamember
+
+    def find_overload(self, name):
+        raise self.missing_attribute_error(name)
+
+    def find_datamember(self, name):
+        raise self.missing_attribute_error(name)
+
+    def get_cppthis(self, cppinstance, calling_scope):
+        assert self == cppinstance.cppclass
+        return cppinstance.get_rawobject()
+
+    def is_namespace(self):
+        return self.space.w_False
+
+    def get_base_names(self):
+        bases = []
+        num_bases = capi.c_num_bases(self)
+        for i in range(num_bases):
+            base_name = capi.c_base_name(self, i)
+            bases.append(self.space.wrap(base_name))
+        return self.space.newlist(bases)
+
+W_CPPClass.typedef = TypeDef(
+    'CPPClass',
+    type_name = interp_attrproperty('name', W_CPPClass),
+    get_base_names = interp2app(W_CPPClass.get_base_names),
+    get_method_names = interp2app(W_CPPClass.get_method_names),
+    get_overload = interp2app(W_CPPClass.get_overload, unwrap_spec=['self', str]),
+    get_datamember_names = interp2app(W_CPPClass.get_datamember_names),
+    get_datamember = interp2app(W_CPPClass.get_datamember, unwrap_spec=['self', str]),
+    is_namespace = interp2app(W_CPPClass.is_namespace),
+    dispatch = interp2app(W_CPPClass.dispatch, unwrap_spec=['self', str, str])
+)
+W_CPPClass.typedef.acceptable_as_base_class = False
+
+
+class W_ComplexCPPClass(W_CPPClass):
+    _immutable_ = True
+
+    def get_cppthis(self, cppinstance, calling_scope):
+        assert self == cppinstance.cppclass
+        offset = capi.c_base_offset(self, calling_scope, cppinstance.get_rawobject(), 1)
+        return capi.direct_ptradd(cppinstance.get_rawobject(), offset)
+
+W_ComplexCPPClass.typedef = TypeDef(
+    'ComplexCPPClass',
+    type_name = interp_attrproperty('name', W_CPPClass),
+    get_base_names = interp2app(W_ComplexCPPClass.get_base_names),
+    get_method_names = interp2app(W_ComplexCPPClass.get_method_names),
+    get_overload = interp2app(W_ComplexCPPClass.get_overload, unwrap_spec=['self', str]),
+    get_datamember_names = interp2app(W_ComplexCPPClass.get_datamember_names),
+    get_datamember = interp2app(W_ComplexCPPClass.get_datamember, unwrap_spec=['self', str]),
+    is_namespace = interp2app(W_ComplexCPPClass.is_namespace),
+    dispatch = interp2app(W_CPPClass.dispatch, unwrap_spec=['self', str, str])
+)
+W_ComplexCPPClass.typedef.acceptable_as_base_class = False
+
+
+class W_CPPTemplateType(Wrappable):
+    _immutable_ = True
+
+    def __init__(self, space, name, opaque_handle):
+        self.space = space
+        self.name = name
+        assert lltype.typeOf(opaque_handle) == capi.C_TYPE
+        self.handle = opaque_handle
+
+    @unwrap_spec(args_w='args_w')
+    def __call__(self, args_w):
+        # TODO: this is broken but unused (see pythonify.py)
+        fullname = "".join([self.name, '<', self.space.str_w(args_w[0]), '>'])
+        return scope_byname(self.space, fullname)
+
+W_CPPTemplateType.typedef = TypeDef(
+    'CPPTemplateType',
+    __call__ = interp2app(W_CPPTemplateType.__call__),
+)
+W_CPPTemplateType.typedef.acceptable_as_base_class = False
+
+
+class W_CPPInstance(Wrappable):
+    _immutable_fields_ = ["cppclass", "isref"]
+
+    def __init__(self, space, cppclass, rawobject, isref, python_owns):
+        self.space = space
+        self.cppclass = cppclass
+        assert lltype.typeOf(rawobject) == capi.C_OBJECT
+        assert not isref or rawobject
+        self._rawobject = rawobject
+        assert not isref or not python_owns
+        self.isref = isref
+        self.python_owns = python_owns
+
+    def _nullcheck(self):
+        if not self._rawobject or (self.isref and not self.get_rawobject()):
+            raise OperationError(self.space.w_ReferenceError,
+                                 self.space.wrap("trying to access a NULL pointer"))
+
+    # allow user to determine ownership rules on a per object level
+    def fget_python_owns(self, space):
+        return space.wrap(self.python_owns)
+
+    @unwrap_spec(value=bool)
+    def fset_python_owns(self, space, value):
+        self.python_owns = space.is_true(value)
+
+    def get_cppthis(self, calling_scope):
+        return self.cppclass.get_cppthis(self, calling_scope)
+
+    def get_rawobject(self):
+        if not self.isref:
+            return self._rawobject
+        else:
+            ptrptr = rffi.cast(rffi.VOIDPP, self._rawobject)
+            return rffi.cast(capi.C_OBJECT, ptrptr[0])
+
+    def instance__eq__(self, w_other):
+        other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False)
+        iseq = self._rawobject == other._rawobject
+        return self.space.wrap(iseq)
+
+    def instance__ne__(self, w_other):
+        return self.space.not_(self.instance__eq__(w_other))
+
+    def instance__nonzero__(self):
+        if not self._rawobject or (self.isref and not self.get_rawobject()):
+            return self.space.w_False
+        return self.space.w_True
+
+    def destruct(self):
+        assert isinstance(self, W_CPPInstance)
+        if self._rawobject and not self.isref:
+            memory_regulator.unregister(self)
+            capi.c_destruct(self.cppclass, self._rawobject)
+            self._rawobject = capi.C_NULL_OBJECT
+
+    def __del__(self):
+        if self.python_owns:
+            self.enqueue_for_destruction(self.space, W_CPPInstance.destruct,
+                                         '__del__() method of ')
+
+W_CPPInstance.typedef = TypeDef(
+    'CPPInstance',
+    cppclass = interp_attrproperty('cppclass', cls=W_CPPInstance),
+    _python_owns = GetSetProperty(W_CPPInstance.fget_python_owns, W_CPPInstance.fset_python_owns),
+    __eq__ = interp2app(W_CPPInstance.instance__eq__),
+    __ne__ = interp2app(W_CPPInstance.instance__ne__),
+    __nonzero__ = interp2app(W_CPPInstance.instance__nonzero__),
+    destruct = interp2app(W_CPPInstance.destruct),
+)
+W_CPPInstance.typedef.acceptable_as_base_class = True
+
+
+class MemoryRegulator:
+    # TODO: (?) An object address is not unique if e.g. the class has a
+    # public data member of class type at the start of its definition and
+    # has no virtual functions. A _key class that hashes on address and
+    # type would be better, but my attempt failed in the rtyper, claiming
+    # a call on None ("None()") and needed a default ctor. (??)
+    # Note that for now, the associated test carries an m_padding to make
+    # a difference in the addresses.
+    def __init__(self):
+        self.objects = rweakref.RWeakValueDictionary(int, W_CPPInstance)
+
+    def register(self, obj):
+        int_address = int(rffi.cast(rffi.LONG, obj._rawobject))
+        self.objects.set(int_address, obj)
+
+    def unregister(self, obj):
+        int_address = int(rffi.cast(rffi.LONG, obj._rawobject))
+        self.objects.set(int_address, None)
+
+    def retrieve(self, address):
+        int_address = int(rffi.cast(rffi.LONG, address))
+        return self.objects.get(int_address)
+
+memory_regulator = MemoryRegulator()
+
+
+def get_pythonized_cppclass(space, handle):
+    state = space.fromcache(State)
+    try:
+        w_pycppclass = state.cppclass_registry[handle]
+    except KeyError:
+        final_name = capi.c_scoped_final_name(handle)
+        w_pycppclass = space.call_function(state.w_clgen_callback, space.wrap(final_name))
+    return w_pycppclass
+
+def wrap_new_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+    if space.is_w(w_pycppclass, space.w_None):
+        w_pycppclass = get_pythonized_cppclass(space, cppclass.handle)
+    w_cppinstance = space.allocate_instance(W_CPPInstance, w_pycppclass)
+    cppinstance = space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=False)
+    W_CPPInstance.__init__(cppinstance, space, cppclass, rawobject, isref, python_owns)
+    memory_regulator.register(cppinstance)
+    return w_cppinstance
+
+def wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+    obj = memory_regulator.retrieve(rawobject)
+    if obj and obj.cppclass == cppclass:
+        return obj
+    return wrap_new_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns)
+
+def wrap_cppobject(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+    if rawobject:
+        actual = capi.c_actual_class(cppclass, rawobject)
+        if actual != cppclass.handle:
+            offset = capi._c_base_offset(actual, cppclass.handle, rawobject, -1)
+            rawobject = capi.direct_ptradd(rawobject, offset)
+            w_pycppclass = get_pythonized_cppclass(space, actual)
+            w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
+            cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+    return wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns)
+
+ at unwrap_spec(cppinstance=W_CPPInstance)
+def addressof(space, cppinstance):
+     address = rffi.cast(rffi.LONG, cppinstance.get_rawobject())
+     return space.wrap(address)
+
+ at unwrap_spec(address=int, owns=bool)
+def bind_object(space, address, w_pycppclass, owns=False):
+    rawobject = rffi.cast(capi.C_OBJECT, address)
+    w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
+    cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+    return wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, False, owns)
diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/pythonify.py
@@ -0,0 +1,388 @@
+# NOT_RPYTHON
+import cppyy
+import types
+
+
+# For now, keep namespaces and classes separate as namespaces are extensible
+# with info from multiple dictionaries and do not need to bother with meta
+# classes for inheritance. Both are python classes, though, and refactoring
+# may be in order at some point.
+class CppyyScopeMeta(type):
+    def __getattr__(self, name):
+        try:
+            return get_pycppitem(self, name)  # will cache on self
+        except TypeError, t:
+            raise AttributeError("%s object has no attribute '%s'" % (self, name))
+
+class CppyyNamespaceMeta(CppyyScopeMeta):
+    pass
+
+class CppyyClass(CppyyScopeMeta):
+    pass
+
+class CPPObject(cppyy.CPPInstance):
+    __metaclass__ = CppyyClass
+
+
+class CppyyTemplateType(object):
+    def __init__(self, scope, name):
+        self._scope = scope
+        self._name = name
+
+    def _arg_to_str(self, arg):
+        if type(arg) != str:
+            arg = arg.__name__
+        return arg
+
+    def __call__(self, *args):
+        fullname = ''.join(
+            [self._name, '<', ','.join(map(self._arg_to_str, args))])
+        if fullname[-1] == '>':
+            fullname += ' >'
+        else:
+            fullname += '>'
+        return getattr(self._scope, fullname)
+
+
+def clgen_callback(name):
+    return get_pycppclass(name)
+cppyy._set_class_generator(clgen_callback)
+
+def make_static_function(func_name, cppol):
+    def function(*args):
+        return cppol.call(None, *args)
+    function.__name__ = func_name
+    function.__doc__ = cppol.signature()
+    return staticmethod(function)
+
+def make_method(meth_name, cppol):
+    def method(self, *args):
+        return cppol.call(self, *args)
+    method.__name__ = meth_name
+    method.__doc__ = cppol.signature()
+    return method
+
+
+def make_datamember(cppdm):
+    rettype = cppdm.get_returntype()
+    if not rettype:                              # return builtin type
+        cppclass = None
+    else:                                        # return instance
+        try:
+            cppclass = get_pycppclass(rettype)
+        except AttributeError:
+            import warnings
+            warnings.warn("class %s unknown: no data member access" % rettype,
+                          RuntimeWarning)
+            cppclass = None
+    if cppdm.is_static():
+        def binder(obj):
+            return cppdm.get(None, cppclass)
+        def setter(obj, value):
+            return cppdm.set(None, value)
+    else:
+        def binder(obj):
+            return cppdm.get(obj, cppclass)
+        setter = cppdm.set
+    return property(binder, setter)
+
+
+def make_cppnamespace(scope, namespace_name, cppns, build_in_full=True):
+    # build up a representation of a C++ namespace (namespaces are classes)
+
+    # create a meta class to allow properties (for static data write access)
+    metans = type(CppyyNamespaceMeta)(namespace_name+'_meta', (CppyyNamespaceMeta,), {})
+
+    if cppns:
+        d = {"_cpp_proxy" : cppns}
+    else:
+        d = dict()
+        def cpp_proxy_loader(cls):
+            cpp_proxy = cppyy._scope_byname(cls.__name__ != '::' and cls.__name__ or '')
+            del cls.__class__._cpp_proxy
+            cls._cpp_proxy = cpp_proxy
+            return cpp_proxy
+        metans._cpp_proxy = property(cpp_proxy_loader)
+
+    # create the python-side C++ namespace representation, cache in scope if given
+    pycppns = metans(namespace_name, (object,), d)
+    if scope:
+        setattr(scope, namespace_name, pycppns)
+
+    if build_in_full:   # if False, rely on lazy build-up
+        # insert static methods into the "namespace" dictionary
+        for func_name in cppns.get_method_names():
+            cppol = cppns.get_overload(func_name)
+            pyfunc = make_static_function(func_name, cppol)
+            setattr(pycppns, func_name, pyfunc)
+
+        # add all data members to the dictionary of the class to be created, and
+        # static ones also to the meta class (needed for property setters)
+        for dm in cppns.get_datamember_names():
+            cppdm = cppns.get_datamember(dm)
+            pydm = make_datamember(cppdm)
+            setattr(pycppns, dm, pydm)
+            setattr(metans, dm, pydm)
+
+    return pycppns
+
+def _drop_cycles(bases):
+    # TODO: figure this out, as it seems to be a PyPy bug?!
+    for b1 in bases:
+        for b2 in bases:
+            if not (b1 is b2) and issubclass(b2, b1):
+                bases.remove(b1)   # removes lateral class
+                break
+    return tuple(bases)
+
+def make_new(class_name, cppclass):
+    try:
+        constructor_overload = cppclass.get_overload(cppclass.type_name)
+    except AttributeError:
+        msg = "cannot instantiate abstract class '%s'" % class_name
+        def __new__(cls, *args):
+            raise TypeError(msg)
+    else:
+        def __new__(cls, *args):
+            return constructor_overload.call(None, *args)
+    return __new__
+
+def make_pycppclass(scope, class_name, final_class_name, cppclass):
+
+    # get a list of base classes for class creation
+    bases = [get_pycppclass(base) for base in cppclass.get_base_names()]
+    if not bases:
+        bases = [CPPObject,]
+    else:
+        # it's technically possible that the required class now has been built
+        # if one of the base classes uses it in e.g. a function interface
+        try:
+            return scope.__dict__[final_class_name]
+        except KeyError:
+            pass
+
+    # create a meta class to allow properties (for static data write access)
+    metabases = [type(base) for base in bases]
+    metacpp = type(CppyyClass)(class_name+'_meta', _drop_cycles(metabases), {})
+
+    # create the python-side C++ class representation
+    def dispatch(self, name, signature):
+        cppol = cppclass.dispatch(name, signature)
+        return types.MethodType(make_method(name, cppol), self, type(self))
+    d = {"_cpp_proxy"   : cppclass,
+         "__dispatch__" : dispatch,
+         "__new__"      : make_new(class_name, cppclass),
+         }
+    pycppclass = metacpp(class_name, _drop_cycles(bases), d)
+ 
+    # cache result early so that the class methods can find the class itself
+    setattr(scope, final_class_name, pycppclass)
+
+    # insert (static) methods into the class dictionary
+    for meth_name in cppclass.get_method_names():
+        cppol = cppclass.get_overload(meth_name)
+        if cppol.is_static():
+            setattr(pycppclass, meth_name, make_static_function(meth_name, cppol))
+        else:
+            setattr(pycppclass, meth_name, make_method(meth_name, cppol))
+
+    # add all data members to the dictionary of the class to be created, and
+    # static ones also to the meta class (needed for property setters)
+    for dm_name in cppclass.get_datamember_names():
+        cppdm = cppclass.get_datamember(dm_name)
+        pydm = make_datamember(cppdm)
+
+        setattr(pycppclass, dm_name, pydm)
+        if cppdm.is_static():
+            setattr(metacpp, dm_name, pydm)
+
+    _pythonize(pycppclass)
+    cppyy._register_class(pycppclass)
+    return pycppclass
+
+def make_cpptemplatetype(scope, template_name):
+    return CppyyTemplateType(scope, template_name)
+
+
+def get_pycppitem(scope, name):
+    # resolve typedefs/aliases
+    full_name = (scope == gbl) and name or (scope.__name__+'::'+name)
+    true_name = cppyy._resolve_name(full_name)
+    if true_name != full_name:
+        return get_pycppclass(true_name)
+
+    pycppitem = None
+
+    # classes
+    cppitem = cppyy._scope_byname(true_name)
+    if cppitem:
+        if cppitem.is_namespace():
+            pycppitem = make_cppnamespace(scope, true_name, cppitem)
+            setattr(scope, name, pycppitem)
+        else:
+            pycppitem = make_pycppclass(scope, true_name, name, cppitem)
+
+    # templates
+    if not cppitem:
+        cppitem = cppyy._template_byname(true_name)
+        if cppitem:
+            pycppitem = make_cpptemplatetype(scope, name)
+            setattr(scope, name, pycppitem)
+
+    # functions
+    if not cppitem:
+        try:
+            cppitem = scope._cpp_proxy.get_overload(name)
+            pycppitem = make_static_function(name, cppitem)
+            setattr(scope.__class__, name, pycppitem)
+            pycppitem = getattr(scope, name)      # binds function as needed
+        except AttributeError:
+            pass
+
+    # data
+    if not cppitem:
+        try:
+            cppitem = scope._cpp_proxy.get_datamember(name)
+            pycppitem = make_datamember(cppitem)
+            setattr(scope, name, pycppitem)
+            if cppitem.is_static():
+                setattr(scope.__class__, name, pycppitem)
+            pycppitem = getattr(scope, name)      # gets actual property value
+        except AttributeError:
+            pass
+
+    if not (pycppitem is None):   # pycppitem could be a bound C++ NULL, so check explicitly for Py_None
+        return pycppitem
+
+    raise AttributeError("'%s' has no attribute '%s'" % (str(scope), name))
+
+
+def scope_splitter(name):
+    is_open_template, scope = 0, ""
+    for c in name:
+        if c == ':' and not is_open_template:
+            if scope:
+                yield scope
+                scope = ""
+            continue
+        elif c == '<':
+            is_open_template += 1
+        elif c == '>':
+            is_open_template -= 1
+        scope += c
+    yield scope
+
+def get_pycppclass(name):
+    # break up the name, to walk the scopes and get the class recursively
+    scope = gbl
+    for part in scope_splitter(name):
+        scope = getattr(scope, part)
+    return scope
+
+
+# pythonization by decoration (move to their own file?)
+def python_style_getitem(self, idx):
+    # python-style indexing: check for size and allow indexing from the back
+    sz = len(self)
+    if idx < 0: idx = sz + idx
+    if idx < sz:
+        return self._getitem__unchecked(idx)
+    raise IndexError('index out of range: %d requested for %s of size %d' % (idx, str(self), sz))
+
+def python_style_sliceable_getitem(self, slice_or_idx):
+    if type(slice_or_idx) == types.SliceType:
+        nseq = self.__class__()
+        nseq += [python_style_getitem(self, i) \
+                    for i in range(*slice_or_idx.indices(len(self)))]
+        return nseq
+    else:
+        return python_style_getitem(self, slice_or_idx)
+
+_pythonizations = {}
+def _pythonize(pyclass):
+
+    try:
+        _pythonizations[pyclass.__name__](pyclass)
+    except KeyError:
+        pass
+
+    # map size -> __len__ (generally true for STL)
+    if hasattr(pyclass, 'size') and \
+            not hasattr(pyclass, '__len__') 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__'):
+        def __iadd__(self, ll):
+            [self.push_back(x) for x in ll]
+            return self
+        pyclass.__iadd__ = __iadd__
+
+    # for STL iterators, whose comparison functions live globally for gcc
+    # TODO: this needs to be solved fundamentally for all classes
+    if 'iterator' in pyclass.__name__:
+        if hasattr(gbl, '__gnu_cxx'):
+            if hasattr(gbl.__gnu_cxx, '__eq__'):
+                setattr(pyclass, '__eq__', gbl.__gnu_cxx.__eq__)
+            if hasattr(gbl.__gnu_cxx, '__ne__'):
+                setattr(pyclass, '__ne__', gbl.__gnu_cxx.__ne__)
+
+    # map begin()/end() protocol to iter protocol
+    if hasattr(pyclass, 'begin') and hasattr(pyclass, 'end'):
+        # TODO: make gnu-independent
+        def __iter__(self):
+            iter = self.begin()
+            while gbl.__gnu_cxx.__ne__(iter, self.end()):
+                yield iter.__deref__()
+                iter.__preinc__()
+            iter.destruct()
+            raise StopIteration
+        pyclass.__iter__ = __iter__
+
+    # combine __getitem__ and __len__ to make a pythonized __getitem__
+    if hasattr(pyclass, '__getitem__') and hasattr(pyclass, '__len__'):
+        pyclass._getitem__unchecked = pyclass.__getitem__
+        if hasattr(pyclass, '__setitem__') and hasattr(pyclass, '__iadd__'):
+            pyclass.__getitem__ = python_style_sliceable_getitem
+        else:
+            pyclass.__getitem__ = python_style_getitem
+
+    # string comparisons (note: CINT backend requires the simple name 'string')
+    if pyclass.__name__ == 'std::basic_string<char>' or pyclass.__name__ == 'string':
+        def eq(self, other):
+            if type(other) == pyclass:
+                return self.c_str() == other.c_str()
+            else:
+                return self.c_str() == other
+        pyclass.__eq__ = eq
+        pyclass.__str__ = pyclass.c_str
+
+    # TODO: clean this up
+    # fixup lack of __getitem__ if no const return
+    if hasattr(pyclass, '__setitem__') and not hasattr(pyclass, '__getitem__'):
+        pyclass.__getitem__ = pyclass.__setitem__
+
+_loaded_dictionaries = {}
+def load_reflection_info(name):
+    try:
+        return _loaded_dictionaries[name]
+    except KeyError:
+        dct = cppyy._load_dictionary(name)
+        _loaded_dictionaries[name] = dct
+        return dct
+    
+
+# user interface objects (note the two-step of not calling scope_byname here:
+# creation of global functions may cause the creation of classes in the global
+# namespace, so gbl must exist at that point to cache them)
+gbl = make_cppnamespace(None, "::", None, False)   # global C++ namespace
+
+# mostly for the benefit of the CINT backend, which treats std as special
+gbl.std = make_cppnamespace(None, "std", None, False)
+
+# user-defined pythonizations interface
+_pythonizations = {}
+def add_pythonization(class_name, callback):
+    if not callable(callback):
+        raise TypeError("given '%s' object is not callable" % str(callback))
+    _pythonizations[class_name] = callback
diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/src/cintcwrapper.cxx
@@ -0,0 +1,791 @@
+#include "cppyy.h"
+#include "cintcwrapper.h"
+
+#include "Api.h"
+
+#include "TROOT.h"
+#include "TError.h"
+#include "TList.h"
+#include "TSystem.h"
+
+#include "TApplication.h"
+#include "TInterpreter.h"
+#include "Getline.h"
+
+#include "TBaseClass.h"
+#include "TClass.h"
+#include "TClassEdit.h"
+#include "TClassRef.h"
+#include "TDataMember.h"
+#include "TFunction.h"
+#include "TGlobal.h"
+#include "TMethod.h"
+#include "TMethodArg.h"
+
+#include <assert.h>
+#include <string.h>
+#include <map>
+#include <sstream>
+#include <string>
+#include <utility>
+
+
+/*  CINT internals (some won't work on Windows) -------------------------- */
+extern long G__store_struct_offset;
+extern "C" void* G__SetShlHandle(char*);
+extern "C" void G__LockCriticalSection();
+extern "C" void G__UnlockCriticalSection();
+
+#define G__SETMEMFUNCENV      (long)0x7fff0035
+#define G__NOP                (long)0x7fff00ff
+
+namespace {
+
+class Cppyy_OpenedTClass : public TDictionary {
+public:
+    mutable TObjArray* fStreamerInfo;    //Array of TVirtualStreamerInfo
+    mutable std::map<std::string, TObjArray*>* fConversionStreamerInfo; //Array of the streamer infos derived from another class.
+    TList*             fRealData;       //linked list for persistent members including base classes
+    TList*             fBase;           //linked list for base classes
+    TList*             fData;           //linked list for data members
+    TList*             fMethod;         //linked list for methods
+    TList*             fAllPubData;     //all public data members (including from base classes)
+    TList*             fAllPubMethod;   //all public methods (including from base classes)
+};
+
+} // unnamed namespace
+
+
+/* data for life time management ------------------------------------------ */
+#define GLOBAL_HANDLE 1l
+
+typedef std::vector<TClassRef> ClassRefs_t;
+static ClassRefs_t g_classrefs(1);
+
+typedef std::map<std::string, ClassRefs_t::size_type> ClassRefIndices_t;
+static ClassRefIndices_t g_classref_indices;
+
+class ClassRefsInit {
+public:
+    ClassRefsInit() {   // setup dummy holders for global and std namespaces
+        assert(g_classrefs.size() == (ClassRefs_t::size_type)GLOBAL_HANDLE);
+        g_classref_indices[""] = (ClassRefs_t::size_type)GLOBAL_HANDLE;
+        g_classrefs.push_back(TClassRef(""));
+        g_classref_indices["std"] = g_classrefs.size();
+        g_classrefs.push_back(TClassRef(""));    // CINT ignores std
+        g_classref_indices["::std"] = g_classrefs.size();
+        g_classrefs.push_back(TClassRef(""));    // id.
+    }
+};
+static ClassRefsInit _classrefs_init;
+
+typedef std::vector<TFunction> GlobalFuncs_t;
+static GlobalFuncs_t g_globalfuncs;
+
+typedef std::vector<TGlobal> GlobalVars_t;
+static GlobalVars_t g_globalvars;
+
+
+/* initialization of the ROOT system (debatable ... ) --------------------- */
+namespace {
+
+class TCppyyApplication : public TApplication {
+public:
+    TCppyyApplication(const char* acn, Int_t* argc, char** argv, Bool_t do_load = kTRUE)
+           : TApplication(acn, argc, argv) {
+
+       // Explicitly load libMathCore as CINT will not auto load it when using one
+       // of its globals. Once moved to Cling, which should work correctly, we
+       // can remove this statement.
+       gSystem->Load("libMathCore");
+
+       if (do_load) {
+            // follow TRint to minimize differences with CINT
+            ProcessLine("#include <iostream>", kTRUE);
+            ProcessLine("#include <_string>",  kTRUE); // for std::string iostream.
+            ProcessLine("#include <DllImport.h>", kTRUE);// Defined R__EXTERN
+            ProcessLine("#include <vector>",   kTRUE); // needed because they're used within the
+            ProcessLine("#include <pair>",     kTRUE); //  core ROOT dicts and CINT won't be able
+                                                       //  to properly unload these files
+        }
+
+        // save current interpreter context
+        gInterpreter->SaveContext();
+        gInterpreter->SaveGlobalsContext();
+
+        // prevent crashes on accessing history
+        Gl_histinit((char*)"-");
+
+        // prevent ROOT from exiting python
+        SetReturnFromRun(kTRUE);
+
+        // enable auto-loader
+        gInterpreter->EnableAutoLoading();
+    }
+};
+
+static const char* appname = "pypy-cppyy";
+
+class ApplicationStarter {
+public:
+    ApplicationStarter() {
+        if (!gApplication) {
+            int argc = 1;
+            char* argv[1]; argv[0] = (char*)appname;
+            gApplication = new TCppyyApplication(appname, &argc, argv, kTRUE);
+        }
+    }
+} _applicationStarter;
+
+} // unnamed namespace
+
+
+/* local helpers ---------------------------------------------------------- */
+static inline char* cppstring_to_cstring(const std::string& name) {
+    char* name_char = (char*)malloc(name.size() + 1);
+    strcpy(name_char, name.c_str());
+    return name_char;
+}
+
+static inline char* type_cppstring_to_cstring(const std::string& tname) {
+    G__TypeInfo ti(tname.c_str());
+    std::string true_name = ti.IsValid() ? ti.TrueName() : tname;
+    return cppstring_to_cstring(true_name);
+}
+
+static inline TClassRef type_from_handle(cppyy_type_t handle) {
+    return g_classrefs[(ClassRefs_t::size_type)handle];
+}
+
+static inline TFunction* type_get_method(cppyy_type_t handle, int method_index) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass())
+        return (TFunction*)cr->GetListOfMethods()->At(method_index);
+    return &g_globalfuncs[method_index];
+}
+
+
+static inline void fixup_args(G__param* libp) {
+    for (int i = 0; i < libp->paran; ++i) {
+        libp->para[i].ref = libp->para[i].obj.i;
+        const char partype = libp->para[i].type;
+        switch (partype) {
+        case 'p': {
+            libp->para[i].obj.i = (long)&libp->para[i].ref;
+            break;
+        }
+        case 'r': {
+            libp->para[i].ref = (long)&libp->para[i].obj.i;
+            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;
+            break;
+        }
+        case 'F': {
+            libp->para[i].ref = (long)&libp->para[i].obj.i;
+            libp->para[i].type = 'f';
+            break;
+        }
+        case 'D': {
+            libp->para[i].ref = (long)&libp->para[i].obj.i;
+            libp->para[i].type = 'd';
+            break;
+
+        }
+        }
+    }
+}
+
+
+/* name to opaque C++ scope representation -------------------------------- */
+char* cppyy_resolve_name(const char* cppitem_name) {
+    if (strcmp(cppitem_name, "") == 0)
+        return cppstring_to_cstring(cppitem_name);
+    G__TypeInfo ti(cppitem_name);
+    if (ti.IsValid()) {
+        if (ti.Property() & G__BIT_ISENUM)
+            return cppstring_to_cstring("unsigned int");
+        return cppstring_to_cstring(ti.TrueName());
+    }
+    return cppstring_to_cstring(cppitem_name);
+}
+
+cppyy_scope_t cppyy_get_scope(const char* scope_name) {
+    ClassRefIndices_t::iterator icr = g_classref_indices.find(scope_name);
+    if (icr != g_classref_indices.end())
+        return (cppyy_type_t)icr->second;
+
+    // use TClass directly, to enable auto-loading
+    TClassRef cr(TClass::GetClass(scope_name, kTRUE, kTRUE));
+    if (!cr.GetClass())
+        return (cppyy_type_t)NULL;
+
+    if (!cr->GetClassInfo())
+        return (cppyy_type_t)NULL;
+
+    if (!G__TypeInfo(scope_name).IsValid())
+        return (cppyy_type_t)NULL;
+
+    ClassRefs_t::size_type sz = g_classrefs.size();
+    g_classref_indices[scope_name] = sz;
+    g_classrefs.push_back(TClassRef(scope_name));
+    return (cppyy_scope_t)sz;
+}
+
+cppyy_type_t cppyy_get_template(const char* template_name) {
+    ClassRefIndices_t::iterator icr = g_classref_indices.find(template_name);
+    if (icr != g_classref_indices.end())
+        return (cppyy_type_t)icr->second;
+
+    if (!G__defined_templateclass((char*)template_name))
+        return (cppyy_type_t)NULL;
+
+    // the following yields a dummy TClassRef, but its name can be queried
+    ClassRefs_t::size_type sz = g_classrefs.size();
+    g_classref_indices[template_name] = sz;
+    g_classrefs.push_back(TClassRef(template_name));
+    return (cppyy_type_t)sz;
+}
+
+cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj) {
+    TClassRef cr = type_from_handle(klass);
+    TClass* clActual = cr->GetActualClass( (void*)obj );
+    if (clActual && clActual != cr.GetClass()) {
+        // TODO: lookup through name should not be needed
+        return (cppyy_type_t)cppyy_get_scope(clActual->GetName());
+    }
+    return klass;
+}
+
+/* memory management ------------------------------------------------------ */
+cppyy_object_t cppyy_allocate(cppyy_type_t handle) {
+    TClassRef cr = type_from_handle(handle);
+    return (cppyy_object_t)malloc(cr->Size());
+}
+
+void cppyy_deallocate(cppyy_type_t /*handle*/, cppyy_object_t instance) {
+    free((void*)instance);
+}
+
+void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) {
+    TClassRef cr = type_from_handle(handle);
+    cr->Destructor((void*)self, true);
+}
+
+
+/* method/function dispatching -------------------------------------------- */
+static inline G__value cppyy_call_T(cppyy_method_t method,
+        cppyy_object_t self, int nargs, void* args) {
+
+    G__InterfaceMethod meth = (G__InterfaceMethod)method;
+    G__param* libp = (G__param*)((char*)args - offsetof(G__param, para));
+    assert(libp->paran == nargs);
+    fixup_args(libp);
+
+    G__value result;
+    G__setnull(&result);
+
+    G__LockCriticalSection();      // CINT-level lock, is recursive
+    G__settemplevel(1);
+
+    long index = (long)&method;
+    G__CurrentCall(G__SETMEMFUNCENV, 0, &index);
+    
+    // TODO: access to store_struct_offset won't work on Windows
+    long store_struct_offset = G__store_struct_offset;
+    if (self)
+        G__store_struct_offset = (long)self;
+
+    meth(&result, 0, libp, 0);
+    if (self)
+        G__store_struct_offset = store_struct_offset;
+
+    if (G__get_return(0) > G__RETURN_NORMAL)
+        G__security_recover(0);    // 0 ensures silence
+
+    G__CurrentCall(G__NOP, 0, 0);
+    G__settemplevel(-1);
+    G__UnlockCriticalSection();
+
+    return result;
+}
+
+void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    cppyy_call_T(method, self, nargs, args);
+}
+
+int cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    G__value result = cppyy_call_T(method, self, nargs, args);
+    return (bool)G__int(result);
+}
+
+char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    G__value result = cppyy_call_T(method, self, nargs, args);
+    return (char)G__int(result);
+}
+
+short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    G__value result = cppyy_call_T(method, self, nargs, args);
+    return (short)G__int(result);
+}
+
+int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    G__value result = cppyy_call_T(method, self, nargs, args);
+    return (int)G__int(result);
+}
+
+long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    G__value result = cppyy_call_T(method, self, nargs, args);
+    return G__int(result);
+}
+
+long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    G__value result = cppyy_call_T(method, self, nargs, args);
+    return G__Longlong(result);
+}
+
+double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    G__value result = cppyy_call_T(method, self, nargs, args);
+    return G__double(result);
+}
+
+double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    G__value result = cppyy_call_T(method, self, nargs, args);
+    return G__double(result);
+}
+
+void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    G__value result = cppyy_call_T(method, self, nargs, args);
+    return (void*)result.ref;
+}
+
+char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    G__value result = cppyy_call_T(method, self, nargs, args);
+    G__pop_tempobject_nodel();
+    if (result.ref && *(long*)result.ref) {
+        char* charp = cppstring_to_cstring(*(std::string*)result.ref);
+        delete (std::string*)result.ref;
+        return charp;
+    }
+    return cppstring_to_cstring("");
+}
+
+void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    G__setgvp((long)self);
+    cppyy_call_T(method, self, nargs, args);
+    G__setgvp((long)G__PVOID);
+}
+
+cppyy_object_t cppyy_call_o(cppyy_type_t method, cppyy_object_t self, int nargs, void* args,
+                  cppyy_type_t /*result_type*/ ) {
+    G__value result = cppyy_call_T(method, self, nargs, args);
+    G__pop_tempobject_nodel();
+    return G__int(result);
+}
+
+cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /*handle*/, int /*method_index*/) {
+    return (cppyy_methptrgetter_t)NULL;
+}
+
+
+/* handling of function argument buffer ----------------------------------- */
+void* cppyy_allocate_function_args(size_t nargs) {
+    assert(sizeof(CPPYY_G__value) == sizeof(G__value));
+    G__param* libp = (G__param*)malloc(
+        offsetof(G__param, para) + nargs*sizeof(CPPYY_G__value));
+    libp->paran = (int)nargs;
+    for (size_t i = 0; i < nargs; ++i)
+        libp->para[i].type = 'l';
+    return (void*)libp->para;
+}
+
+void cppyy_deallocate_function_args(void* args) {
+    free((char*)args - offsetof(G__param, para));
+}
+
+size_t cppyy_function_arg_sizeof() {
+    return sizeof(CPPYY_G__value);
+}
+
+size_t cppyy_function_arg_typeoffset() {
+    return offsetof(CPPYY_G__value, type);
+}
+
+
+/* scope reflection information ------------------------------------------- */
+int cppyy_is_namespace(cppyy_scope_t handle) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass() && cr->GetClassInfo())
+        return cr->Property() & G__BIT_ISNAMESPACE;
+    if (strcmp(cr.GetClassName(), "") == 0)
+        return true;
+    return false;
+}
+
+int cppyy_is_enum(const char* type_name) {
+    G__TypeInfo ti(type_name);
+    return (ti.Property() & G__BIT_ISENUM);
+}
+
+
+/* type/class reflection information -------------------------------------- */
+char* cppyy_final_name(cppyy_type_t handle) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass() && cr->GetClassInfo()) {
+        std::string true_name = G__TypeInfo(cr->GetName()).TrueName();
+        std::string::size_type pos = true_name.rfind("::");
+        if (pos != std::string::npos)
+            return cppstring_to_cstring(true_name.substr(pos+2, std::string::npos));
+        return cppstring_to_cstring(true_name);
+    }
+    return cppstring_to_cstring(cr.GetClassName());
+}
+
+char* cppyy_scoped_final_name(cppyy_type_t handle) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass() && cr->GetClassInfo()) {
+        std::string true_name = G__TypeInfo(cr->GetName()).TrueName();
+        return cppstring_to_cstring(true_name);
+    }
+    return cppstring_to_cstring(cr.GetClassName());
+}
+
+int cppyy_has_complex_hierarchy(cppyy_type_t handle) {
+// as long as no fast path is supported for CINT, calculating offsets (which
+// are cached by the JIT) is not going to hurt 
+    return 1;
+}
+
+int cppyy_num_bases(cppyy_type_t handle) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass() && cr->GetListOfBases() != 0)
+        return cr->GetListOfBases()->GetSize();
+    return 0;
+}
+
+char* cppyy_base_name(cppyy_type_t handle, int base_index) {
+    TClassRef cr = type_from_handle(handle);
+    TBaseClass* b = (TBaseClass*)cr->GetListOfBases()->At(base_index);
+    return type_cppstring_to_cstring(b->GetName());
+}
+
+int cppyy_is_subtype(cppyy_type_t derived_handle, cppyy_type_t base_handle) {
+    TClassRef derived_type = type_from_handle(derived_handle);
+    TClassRef base_type = type_from_handle(base_handle);
+    return derived_type->GetBaseClass(base_type) != 0;
+}
+
+size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle,
+                       cppyy_object_t address, int /* direction */) {
+    // WARNING: CINT can not handle actual dynamic casts!
+    TClassRef derived_type = type_from_handle(derived_handle);
+    TClassRef base_type = type_from_handle(base_handle);
+
+    long offset = 0;
+
+    if (derived_type && base_type) {
+        G__ClassInfo* base_ci    = (G__ClassInfo*)base_type->GetClassInfo();
+        G__ClassInfo* derived_ci = (G__ClassInfo*)derived_type->GetClassInfo();
+
+        if (base_ci && derived_ci) {
+#ifdef WIN32
+            // Windows cannot cast-to-derived for virtual inheritance
+            // with CINT's (or Reflex's) interfaces.
+            long baseprop = derived_ci->IsBase(*base_ci);
+            if (!baseprop || (baseprop & G__BIT_ISVIRTUALBASE))
+                offset = derived_type->GetBaseClassOffset(base_type);
+            else
+#endif
+                offset = G__isanybase(base_ci->Tagnum(), derived_ci->Tagnum(), (long)address);
+         } else {
+             offset = derived_type->GetBaseClassOffset(base_type);
+         }
+    }
+
+    return (size_t) offset;   // may be negative (will roll over)
+}
+
+
+/* method/function reflection information --------------------------------- */
+int cppyy_num_methods(cppyy_scope_t handle) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass() && cr->GetListOfMethods())
+        return cr->GetListOfMethods()->GetSize();
+    else if (strcmp(cr.GetClassName(), "") == 0) {
+    // NOTE: the updated list of global funcs grows with 5 "G__ateval"'s just
+    // because it is being updated => infinite loop! Apply offset to correct ...
+        static int ateval_offset = 0;
+        TCollection* funcs = gROOT->GetListOfGlobalFunctions(kTRUE);
+        ateval_offset += 5;
+	if (g_globalfuncs.size() <= (GlobalFuncs_t::size_type)funcs->GetSize() - ateval_offset) {
+            g_globalfuncs.clear();
+	    g_globalfuncs.reserve(funcs->GetSize());
+
+            TIter ifunc(funcs);
+
+            TFunction* func = 0;
+            while ((func = (TFunction*)ifunc.Next())) {
+                if (strcmp(func->GetName(), "G__ateval") == 0)
+                    ateval_offset += 1;
+                else
+                    g_globalfuncs.push_back(*func);
+            }
+        }
+	return (int)g_globalfuncs.size();
+    }
+    return 0;
+}
+
+char* cppyy_method_name(cppyy_scope_t handle, int method_index) {
+    TFunction* f = type_get_method(handle, method_index);
+    return cppstring_to_cstring(f->GetName());
+}
+
+char* cppyy_method_result_type(cppyy_scope_t handle, int method_index) {
+    TFunction* f = 0;
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass()) {
+        if (cppyy_is_constructor(handle, method_index))
+            return cppstring_to_cstring("constructor");
+        f = (TFunction*)cr->GetListOfMethods()->At(method_index);
+    } else
+        f = &g_globalfuncs[method_index];
+    return type_cppstring_to_cstring(f->GetReturnTypeName());
+}
+
+int cppyy_method_num_args(cppyy_scope_t handle, int method_index) {
+    TFunction* f = type_get_method(handle, method_index);
+    return f->GetNargs();
+}
+
+int cppyy_method_req_args(cppyy_scope_t handle, int method_index) {
+    TFunction* f = type_get_method(handle, method_index);
+    return f->GetNargs() - f->GetNargsOpt();
+}
+
+char* cppyy_method_arg_type(cppyy_scope_t handle, int method_index, int arg_index) {
+    TFunction* f = type_get_method(handle, method_index);
+    TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At(arg_index);
+    return type_cppstring_to_cstring(arg->GetFullTypeName());
+}
+
+char* cppyy_method_arg_default(cppyy_scope_t, int, int) {
+    /* unused: libffi does not work with CINT back-end */
+    return cppstring_to_cstring("");
+}
+
+char* cppyy_method_signature(cppyy_scope_t handle, int method_index) {
+    TFunction* f = type_get_method(handle, method_index);
+    TClassRef cr = type_from_handle(handle);
+    std::ostringstream sig;
+    if (cr.GetClass() && cr->GetClassInfo()
+        && strcmp(f->GetName(), ((G__ClassInfo*)cr->GetClassInfo())->Name()) != 0)
+        sig << f->GetReturnTypeName() << " ";
+    sig << cr.GetClassName() << "::" << f->GetName() << "(";
+    int nArgs = f->GetNargs();
+    for (int iarg = 0; iarg < nArgs; ++iarg) {
+        sig << ((TMethodArg*)f->GetListOfMethodArgs()->At(iarg))->GetFullTypeName();
+        if (iarg != nArgs-1)
+            sig << ", ";
+    }
+    sig << ")" << std::ends;
+    return cppstring_to_cstring(sig.str());
+}
+
+int cppyy_method_index(cppyy_scope_t handle, const char* name) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass()) {
+        gInterpreter->UpdateListOfMethods(cr.GetClass());
+        int imeth = 0;
+        TFunction* func;
+        TIter next(cr->GetListOfMethods());
+        while ((func = (TFunction*)next())) {
+            if (strcmp(name, func->GetName()) == 0) {
+                if (func->Property() & G__BIT_ISPUBLIC)
+                    return imeth;
+                return -1;
+            }
+            ++imeth;
+        }
+    }
+    TFunction* func = gROOT->GetGlobalFunction(name, NULL, kTRUE);
+    if (!func)
+        return -1;
+    int idx = g_globalfuncs.size();
+    g_globalfuncs.push_back(*func);
+    return idx;
+}
+
+cppyy_method_t cppyy_get_method(cppyy_scope_t handle, int method_index) {
+    TFunction* f = type_get_method(handle, method_index);
+    return (cppyy_method_t)f->InterfaceMethod();
+}
+
+
+/* method properties -----------------------------------------------------  */
+int cppyy_is_constructor(cppyy_type_t handle, int method_index) {
+    TClassRef cr = type_from_handle(handle);
+    TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index);
+    return strcmp(m->GetName(), ((G__ClassInfo*)cr->GetClassInfo())->Name()) == 0;
+}
+
+int cppyy_is_staticmethod(cppyy_type_t handle, int method_index) {
+    TClassRef cr = type_from_handle(handle);
+    TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index);
+    return m->Property() & G__BIT_ISSTATIC;
+}
+
+
+/* data member reflection information ------------------------------------- */
+int cppyy_num_datamembers(cppyy_scope_t handle) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass() && cr->GetListOfDataMembers())
+        return cr->GetListOfDataMembers()->GetSize();
+    else if (strcmp(cr.GetClassName(), "") == 0) {
+        TCollection* vars = gROOT->GetListOfGlobals(kTRUE);
+       	if (g_globalvars.size() != (GlobalVars_t::size_type)vars->GetSize()) {
+            g_globalvars.clear();
+	    g_globalvars.reserve(vars->GetSize());
+
+            TIter ivar(vars);
+
+            TGlobal* var = 0;
+            while ((var = (TGlobal*)ivar.Next()))
+                g_globalvars.push_back(*var);
+
+        }
+	return (int)g_globalvars.size();
+    }
+    return 0;
+}
+
+char* cppyy_datamember_name(cppyy_scope_t handle, int datamember_index) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass()) {
+        TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+        return cppstring_to_cstring(m->GetName());
+    }
+    TGlobal& gbl = g_globalvars[datamember_index];
+    return cppstring_to_cstring(gbl.GetName());
+}
+
+char* cppyy_datamember_type(cppyy_scope_t handle, int datamember_index) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass())  {
+        TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+        std::string fullType = m->GetFullTypeName();
+        if ((int)m->GetArrayDim() > 1 || (!m->IsBasic() && m->IsaPointer()))
+            fullType.append("*");
+        else if ((int)m->GetArrayDim() == 1) {
+            std::ostringstream s;
+            s << '[' << m->GetMaxIndex(0) << ']' << std::ends;
+            fullType.append(s.str());
+        }
+        return cppstring_to_cstring(fullType);
+    }
+    TGlobal& gbl = g_globalvars[datamember_index];
+    return cppstring_to_cstring(gbl.GetFullTypeName());
+}
+
+size_t cppyy_datamember_offset(cppyy_scope_t handle, int datamember_index) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass()) {
+        TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+        return (size_t)m->GetOffsetCint();
+    }
+    TGlobal& gbl = g_globalvars[datamember_index];
+    return (size_t)gbl.GetAddress();
+}
+
+int cppyy_datamember_index(cppyy_scope_t handle, const char* name) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass()) {
+        // called from updates; add a hard reset as the code itself caches in
+        // Class (TODO: by-pass ROOT/meta)
+        Cppyy_OpenedTClass* c = (Cppyy_OpenedTClass*)cr.GetClass();
+        if (c->fData) {
+            c->fData->Delete();
+            delete c->fData; c->fData = 0;
+            delete c->fAllPubData; c->fAllPubData = 0;
+        }
+        // the following appears dumb, but TClass::GetDataMember() does a linear
+        // search itself, so there is no gain
+        int idm = 0;
+        TDataMember* dm;
+        TIter next(cr->GetListOfDataMembers());
+        while ((dm = (TDataMember*)next())) {
+            if (strcmp(name, dm->GetName()) == 0) {
+                if (dm->Property() & G__BIT_ISPUBLIC)
+                    return idm;
+                return -1;
+            }
+            ++idm;
+        }
+    }
+    TGlobal* gbl = (TGlobal*)gROOT->GetListOfGlobals(kTRUE)->FindObject(name);
+    if (!gbl)
+        return -1;
+    int idx = g_globalvars.size();
+    g_globalvars.push_back(*gbl);
+    return idx;
+}
+
+
+/* data member properties ------------------------------------------------  */
+int cppyy_is_publicdata(cppyy_scope_t handle, int datamember_index) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass()) {
+        TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+        return m->Property() & G__BIT_ISPUBLIC;
+    }
+    return 1;  // global data is always public
+}
+
+int cppyy_is_staticdata(cppyy_scope_t handle, int datamember_index) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass()) {
+        TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+        return m->Property() & G__BIT_ISSTATIC;
+    }
+    return 1;  // global data is always static
+}
+
+
+/* misc helpers ----------------------------------------------------------- */
+long long cppyy_strtoll(const char* str) {
+    return strtoll(str, NULL, 0);
+}
+
+extern "C" unsigned long long cppyy_strtoull(const char* str) {
+    return strtoull(str, NULL, 0);
+}
+
+void cppyy_free(void* ptr) {
+    free(ptr);
+}
+
+cppyy_object_t cppyy_charp2stdstring(const char* str) {
+    return (cppyy_object_t)new std::string(str);
+}
+
+cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr) {
+    return (cppyy_object_t)new std::string(*(std::string*)ptr);
+}
+
+void cppyy_free_stdstring(cppyy_object_t ptr) {
+    delete (std::string*)ptr;
+}
+
+void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str) {
+   *((std::string*)ptr) = str;
+}
+
+void* cppyy_load_dictionary(const char* lib_name) {
+    if (0 <= gSystem->Load(lib_name))
+        return (void*)1;
+    return (void*)0;
+}
diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/src/reflexcwrapper.cxx
@@ -0,0 +1,541 @@
+#include "cppyy.h"
+#include "reflexcwrapper.h"
+
+#include "Reflex/Kernel.h"
+#include "Reflex/Type.h"
+#include "Reflex/Base.h"
+#include "Reflex/Member.h"
+#include "Reflex/Object.h"
+#include "Reflex/Builder/TypeBuilder.h"
+#include "Reflex/PropertyList.h"
+#include "Reflex/TypeTemplate.h"
+
+#define private public
+#include "Reflex/PluginService.h"
+#undef private
+
+#include <string>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <assert.h>
+#include <stdlib.h>
+
+
+/* local helpers ---------------------------------------------------------- */
+static inline char* cppstring_to_cstring(const std::string& name) {
+    char* name_char = (char*)malloc(name.size() + 1);
+    strcpy(name_char, name.c_str());
+    return name_char;
+}
+
+static inline Reflex::Scope scope_from_handle(cppyy_type_t handle) {
+    return Reflex::Scope((Reflex::ScopeName*)handle);
+}
+
+static inline Reflex::Type type_from_handle(cppyy_type_t handle) {
+    return Reflex::Scope((Reflex::ScopeName*)handle);
+}
+
+static inline std::vector<void*> build_args(int nargs, void* args) {
+    std::vector<void*> arguments;
+    arguments.reserve(nargs);
+    for (int i = 0; i < nargs; ++i) {
+	char tc = ((CPPYY_G__value*)args)[i].type;
+        if (tc != 'a' && tc != 'o')
+            arguments.push_back(&((CPPYY_G__value*)args)[i]);
+        else
+            arguments.push_back((void*)(*(long*)&((CPPYY_G__value*)args)[i]));
+    }
+    return arguments;
+}
+
+
+/* name to opaque C++ scope representation -------------------------------- */
+char* cppyy_resolve_name(const char* cppitem_name) {
+    Reflex::Scope s = Reflex::Scope::ByName(cppitem_name);
+    if (s.IsEnum())
+        return cppstring_to_cstring("unsigned int");
+    const std::string& name = s.Name(Reflex::SCOPED|Reflex::QUALIFIED|Reflex::FINAL);
+    if (name.empty())
+        return cppstring_to_cstring(cppitem_name);
+    return cppstring_to_cstring(name);
+}
+
+cppyy_scope_t cppyy_get_scope(const char* scope_name) {
+    Reflex::Scope s = Reflex::Scope::ByName(scope_name);
+    if (!s) Reflex::PluginService::Instance().LoadFactoryLib(scope_name);
+    s = Reflex::Scope::ByName(scope_name);
+    if (s.IsEnum())     // pretend to be builtin by returning 0
+        return (cppyy_type_t)0;
+    return (cppyy_type_t)s.Id();
+}
+
+cppyy_type_t cppyy_get_template(const char* template_name) {
+   Reflex::TypeTemplate tt = Reflex::TypeTemplate::ByName(template_name);
+   return (cppyy_type_t)tt.Id();
+}
+
+cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj) {
+    Reflex::Type t = type_from_handle(klass);
+    Reflex::Type tActual = t.DynamicType(Reflex::Object(t, (void*)obj));
+    if (tActual && tActual != t) {
+        // TODO: lookup through name should not be needed (but tActual.Id()
+        // does not return a singular Id for the system :( )
+        return (cppyy_type_t)cppyy_get_scope(tActual.Name().c_str());
+    }
+    return klass;
+}
+
+
+/* memory management ------------------------------------------------------ */
+cppyy_object_t cppyy_allocate(cppyy_type_t handle) {
+    Reflex::Type t = type_from_handle(handle);
+    return (cppyy_object_t)t.Allocate();
+}
+
+void cppyy_deallocate(cppyy_type_t handle, cppyy_object_t instance) {
+    Reflex::Type t = type_from_handle(handle);
+    t.Deallocate((void*)instance);
+}
+
+void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) {
+    Reflex::Type t = type_from_handle(handle);
+    t.Destruct((void*)self, true);
+}
+
+
+/* method/function dispatching -------------------------------------------- */
+void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    std::vector<void*> arguments = build_args(nargs, args);
+    Reflex::StubFunction stub = (Reflex::StubFunction)method;
+    stub(NULL /* return address */, (void*)self, arguments, NULL /* stub context */);
+}
+
+template<typename T>
+static inline T cppyy_call_T(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    T result;
+    std::vector<void*> arguments = build_args(nargs, args);
+    Reflex::StubFunction stub = (Reflex::StubFunction)method;
+    stub(&result, (void*)self, arguments, NULL /* stub context */);
+    return result;
+}
+
+int cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    return (int)cppyy_call_T<bool>(method, self, nargs, args);
+}
+
+char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    return cppyy_call_T<char>(method, self, nargs, args);
+}
+
+short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    return cppyy_call_T<short>(method, self, nargs, args);
+}
+
+int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    return cppyy_call_T<int>(method, self, nargs, args);
+}
+
+long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    return cppyy_call_T<long>(method, self, nargs, args);
+}
+
+long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    return cppyy_call_T<long long>(method, self, nargs, args);
+}
+
+double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    return cppyy_call_T<float>(method, self, nargs, args);
+}
+
+double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    return cppyy_call_T<double>(method, self, nargs, args);
+}   
+
+void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    return (void*)cppyy_call_T<long>(method, self, nargs, args);
+}
+
+char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    std::string result("");
+    std::vector<void*> arguments = build_args(nargs, args);
+    Reflex::StubFunction stub = (Reflex::StubFunction)method;
+    stub(&result, (void*)self, arguments, NULL /* stub context */);
+    return cppstring_to_cstring(result);
+}
+
+void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    cppyy_call_v(method, self, nargs, args);
+}
+
+cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args,
+                  cppyy_type_t result_type) {
+    void* result = (void*)cppyy_allocate(result_type);
+    std::vector<void*> arguments = build_args(nargs, args);
+    Reflex::StubFunction stub = (Reflex::StubFunction)method;
+    stub(result, (void*)self, arguments, NULL /* stub context */);
+    return (cppyy_object_t)result;
+}
+
+static cppyy_methptrgetter_t get_methptr_getter(Reflex::Member m) {
+    Reflex::PropertyList plist = m.Properties();
+    if (plist.HasProperty("MethPtrGetter")) {
+        Reflex::Any& value = plist.PropertyValue("MethPtrGetter");
+        return (cppyy_methptrgetter_t)Reflex::any_cast<void*>(value);
+    }
+    return 0;
+}
+
+cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t handle, int method_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.FunctionMemberAt(method_index);
+    return get_methptr_getter(m);
+}
+
+
+/* handling of function argument buffer ----------------------------------- */
+void* cppyy_allocate_function_args(size_t nargs) {
+    CPPYY_G__value* args = (CPPYY_G__value*)malloc(nargs*sizeof(CPPYY_G__value));
+    for (size_t i = 0; i < nargs; ++i)
+        args[i].type = 'l';
+    return (void*)args;
+}
+
+void cppyy_deallocate_function_args(void* args) {
+    free(args);
+}
+
+size_t cppyy_function_arg_sizeof() {
+    return sizeof(CPPYY_G__value);
+}
+
+size_t cppyy_function_arg_typeoffset() {
+    return offsetof(CPPYY_G__value, type);
+}
+
+
+/* scope reflection information ------------------------------------------- */
+int cppyy_is_namespace(cppyy_scope_t handle) {
+    Reflex::Scope s = scope_from_handle(handle);
+    return s.IsNamespace();
+}
+
+int cppyy_is_enum(const char* type_name) {
+    Reflex::Type t = Reflex::Type::ByName(type_name);
+    return t.IsEnum();
+}
+
+
+/* class reflection information ------------------------------------------- */
+char* cppyy_final_name(cppyy_type_t handle) {
+    Reflex::Scope s = scope_from_handle(handle);
+    if (s.IsEnum())
+        return cppstring_to_cstring("unsigned int");
+    std::string name = s.Name(Reflex::FINAL);
+    return cppstring_to_cstring(name);
+}
+
+char* cppyy_scoped_final_name(cppyy_type_t handle) {
+    Reflex::Scope s = scope_from_handle(handle);
+    if (s.IsEnum())
+        return cppstring_to_cstring("unsigned int");
+    std::string name = s.Name(Reflex::SCOPED | Reflex::FINAL);
+    return cppstring_to_cstring(name);
+}   
+
+static int cppyy_has_complex_hierarchy(const Reflex::Type& t) {
+    int is_complex = 1;
+    
+    size_t nbases = t.BaseSize();
+    if (1 < nbases)
+        is_complex = 1;
+    else if (nbases == 0)
+        is_complex = 0;
+    else {         // one base class only
+        Reflex::Base b = t.BaseAt(0);
+        if (b.IsVirtual())
+            is_complex = 1;       // TODO: verify; can be complex, need not be.
+        else
+            is_complex = cppyy_has_complex_hierarchy(t.BaseAt(0).ToType());
+    }
+
+    return is_complex;
+}   
+
+int cppyy_has_complex_hierarchy(cppyy_type_t handle) {
+    Reflex::Type t = type_from_handle(handle);
+    return cppyy_has_complex_hierarchy(t);
+}
+
+int cppyy_num_bases(cppyy_type_t handle) {
+    Reflex::Type t = type_from_handle(handle);
+    return t.BaseSize();
+}
+
+char* cppyy_base_name(cppyy_type_t handle, int base_index) {
+    Reflex::Type t = type_from_handle(handle);
+    Reflex::Base b = t.BaseAt(base_index);
+    std::string name = b.Name(Reflex::FINAL|Reflex::SCOPED);
+    return cppstring_to_cstring(name);
+}
+
+int cppyy_is_subtype(cppyy_type_t derived_handle, cppyy_type_t base_handle) {
+    Reflex::Type derived_type = type_from_handle(derived_handle);
+    Reflex::Type base_type = type_from_handle(base_handle);
+    return (int)derived_type.HasBase(base_type);
+}
+
+size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle,
+                       cppyy_object_t address, int direction) {
+    Reflex::Type derived_type = type_from_handle(derived_handle);
+    Reflex::Type base_type = type_from_handle(base_handle);
+
+    // when dealing with virtual inheritance the only (reasonably) well-defined info is
+    // in a Reflex internal base table, that contains all offsets within the hierarchy
+    Reflex::Member getbases = derived_type.FunctionMemberByName(
+           "__getBasesTable", Reflex::Type(), 0, Reflex::INHERITEDMEMBERS_NO, Reflex::DELAYEDLOAD_OFF);
+    if (getbases) {
+        typedef std::vector<std::pair<Reflex::Base, int> > Bases_t;
+        Bases_t* bases;
+        Reflex::Object bases_holder(Reflex::Type::ByTypeInfo(typeid(Bases_t)), &bases);
+        getbases.Invoke(&bases_holder);
+
+        // if direction is down-cast, perform the cast in C++ first in order to ensure
+        // we have a derived object for accessing internal offset pointers
+        if (direction < 0) {
+           Reflex::Object o(base_type, (void*)address);
+           address = (cppyy_object_t)o.CastObject(derived_type).Address();
+        }
+
+        for (Bases_t::iterator ibase = bases->begin(); ibase != bases->end(); ++ibase) {
+            if (ibase->first.ToType() == base_type) {
+                long offset = (long)ibase->first.Offset((void*)address);
+                if (direction < 0)
+                   return (size_t) -offset;  // note negative; rolls over
+                return (size_t)offset;
+            }
+        }
+
+        // contrary to typical invoke()s, the result of the internal getbases function
+        // is a pointer to a function static, so no delete
+    }
+
+    return 0;
+}
+
+
+/* method/function reflection information --------------------------------- */
+int cppyy_num_methods(cppyy_scope_t handle) {
+    Reflex::Scope s = scope_from_handle(handle);
+    return s.FunctionMemberSize();
+}
+
+char* cppyy_method_name(cppyy_scope_t handle, int method_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.FunctionMemberAt(method_index);
+    std::string name;
+    if (m.IsConstructor())
+        name = s.Name(Reflex::FINAL);   // to get proper name for templates
+    else
+        name = m.Name();
+    return cppstring_to_cstring(name);
+}
+
+char* cppyy_method_result_type(cppyy_scope_t handle, int method_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.FunctionMemberAt(method_index);
+    if (m.IsConstructor())
+        return cppstring_to_cstring("constructor");
+    Reflex::Type rt = m.TypeOf().ReturnType();
+    std::string name = rt.Name(Reflex::FINAL|Reflex::SCOPED|Reflex::QUALIFIED);
+    return cppstring_to_cstring(name);
+}
+
+int cppyy_method_num_args(cppyy_scope_t handle, int method_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.FunctionMemberAt(method_index);
+    return m.FunctionParameterSize();
+}
+
+int cppyy_method_req_args(cppyy_scope_t handle, int method_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.FunctionMemberAt(method_index);
+    return m.FunctionParameterSize(true);
+}
+
+char* cppyy_method_arg_type(cppyy_scope_t handle, int method_index, int arg_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.FunctionMemberAt(method_index);
+    Reflex::Type at = m.TypeOf().FunctionParameterAt(arg_index);
+    std::string name = at.Name(Reflex::FINAL|Reflex::SCOPED|Reflex::QUALIFIED);
+    return cppstring_to_cstring(name);
+}
+
+char* cppyy_method_arg_default(cppyy_scope_t handle, int method_index, int arg_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.FunctionMemberAt(method_index);
+    std::string dflt = m.FunctionParameterDefaultAt(arg_index);
+    return cppstring_to_cstring(dflt);
+}
+
+char* cppyy_method_signature(cppyy_scope_t handle, int method_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.FunctionMemberAt(method_index);
+    Reflex::Type mt = m.TypeOf();
+    std::ostringstream sig;
+    if (!m.IsConstructor())
+        sig << mt.ReturnType().Name() << " ";
+    sig << s.Name(Reflex::SCOPED) << "::" << m.Name() << "(";
+    int nArgs = m.FunctionParameterSize();
+    for (int iarg = 0; iarg < nArgs; ++iarg) {
+        sig << mt.FunctionParameterAt(iarg).Name(Reflex::SCOPED|Reflex::QUALIFIED);
+        if (iarg != nArgs-1)
+            sig << ", ";
+    }
+    sig << ")" << std::ends;
+    return cppstring_to_cstring(sig.str());
+}
+
+int cppyy_method_index(cppyy_scope_t handle, const char* name) {
+    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
+    // Scope::FunctionMemberByName() function
+    int num_meth = s.FunctionMemberSize();
+    for (int imeth = 0; imeth < num_meth; ++imeth) {
+        Reflex::Member m = s.FunctionMemberAt(imeth);
+        if (m.Name() == name) {
+            if (m.IsPublic())
+                return imeth;
+            return -1;
+        }
+    }
+    return -1;
+}
+
+cppyy_method_t cppyy_get_method(cppyy_scope_t handle, int method_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.FunctionMemberAt(method_index);
+    assert(m.IsFunctionMember());
+    return (cppyy_method_t)m.Stubfunction();
+}
+
+
+/* method properties -----------------------------------------------------  */
+int cppyy_is_constructor(cppyy_type_t handle, int method_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.FunctionMemberAt(method_index);
+    return m.IsConstructor();
+}
+
+int cppyy_is_staticmethod(cppyy_type_t handle, int method_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.FunctionMemberAt(method_index);
+    return m.IsStatic();
+}
+
+
+/* data member reflection information ------------------------------------- */
+int cppyy_num_datamembers(cppyy_scope_t handle) {
+    Reflex::Scope s = scope_from_handle(handle);
+    // fix enum representation by adding them to the containing scope as per C++
+    // TODO: this (relatively harmlessly) dupes data members when updating in the
+    //       case s is a namespace
+    for (int isub = 0; isub < (int)s.ScopeSize(); ++isub) {
+        Reflex::Scope sub = s.SubScopeAt(isub);
+        if (sub.IsEnum()) {
+            for (int idata = 0;  idata < (int)sub.DataMemberSize(); ++idata) {
+                Reflex::Member m = sub.DataMemberAt(idata);
+                s.AddDataMember(m.Name().c_str(), sub, 0,
+                                Reflex::PUBLIC|Reflex::STATIC|Reflex::ARTIFICIAL,
+                                (char*)m.Offset());
+            }
+        }
+    }
+    return s.DataMemberSize();
+}
+
+char* cppyy_datamember_name(cppyy_scope_t handle, int datamember_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.DataMemberAt(datamember_index);
+    std::string name = m.Name();
+    return cppstring_to_cstring(name);
+}
+
+char* cppyy_datamember_type(cppyy_scope_t handle, int datamember_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.DataMemberAt(datamember_index);
+    std::string name = m.TypeOf().Name(Reflex::FINAL|Reflex::SCOPED|Reflex::QUALIFIED);
+    return cppstring_to_cstring(name);
+}
+
+size_t cppyy_datamember_offset(cppyy_scope_t handle, int datamember_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.DataMemberAt(datamember_index);
+    if (m.IsArtificial() && m.TypeOf().IsEnum())
+        return (size_t)&m.InterpreterOffset();
+    return m.Offset();
+}
+
+int cppyy_datamember_index(cppyy_scope_t handle, const char* name) {
+    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
+    // Scope::DataMemberByName() function (which returns Member, not an index)
+    int num_dm = cppyy_num_datamembers(handle);
+    for (int idm = 0; idm < num_dm; ++idm) {
+        Reflex::Member m = s.DataMemberAt(idm);
+        if (m.Name() == name || m.Name(Reflex::FINAL) == name) {
+            if (m.IsPublic())
+                return idm;
+            return -1;
+        }
+    }
+    return -1;
+}
+
+
+/* data member properties ------------------------------------------------  */
+int cppyy_is_publicdata(cppyy_scope_t handle, int datamember_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.DataMemberAt(datamember_index);
+    return m.IsPublic();
+}
+
+int cppyy_is_staticdata(cppyy_scope_t handle, int datamember_index) {
+    Reflex::Scope s = scope_from_handle(handle);
+    Reflex::Member m = s.DataMemberAt(datamember_index);
+    return m.IsStatic();
+}
+
+
+/* misc helpers ----------------------------------------------------------- */
+long long cppyy_strtoll(const char* str) {
+    return strtoll(str, NULL, 0);
+}
+
+extern "C" unsigned long long cppyy_strtoull(const char* str) {
+    return strtoull(str, NULL, 0);
+}
+
+void cppyy_free(void* ptr) {
+    free(ptr);
+}
+
+cppyy_object_t cppyy_charp2stdstring(const char* str) {
+    return (cppyy_object_t)new std::string(str);
+}
+
+cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr) {
+    return (cppyy_object_t)new std::string(*(std::string*)ptr);
+}
+
+void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str) {
+   *((std::string*)ptr) = str;
+}
+
+void cppyy_free_stdstring(cppyy_object_t ptr) {
+    delete (std::string*)ptr;
+}
diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/Makefile
@@ -0,0 +1,62 @@
+dicts = example01Dict.so datatypesDict.so advancedcppDict.so advancedcpp2Dict.so \
+overloadsDict.so stltypesDict.so operatorsDict.so fragileDict.so crossingDict.so \
+std_streamsDict.so
+all : $(dicts)
+
+ROOTSYS := ${ROOTSYS}
+
+ifeq ($(ROOTSYS),)
+  genreflex=genreflex
+  cppflags=
+else
+  genreflex=$(ROOTSYS)/bin/genreflex
+  ifeq ($(wildcard $(ROOTSYS)/include),)     # standard locations used?
+    cppflags=-I$(shell root-config --incdir) -L$(shell root-config --libdir)
+  else
+    cppflags=-I$(ROOTSYS)/include -L$(ROOTSYS)/lib64 -L$(ROOTSYS)/lib
+  endif
+endif
+
+PLATFORM := $(shell uname -s)
+ifeq ($(PLATFORM),Darwin)
+  cppflags+=-dynamiclib -single_module -arch x86_64
+endif
+
+ifeq ($(CINT),)
+  ifeq ($(shell $(genreflex) --help | grep -- --with-methptrgetter),)
+    genreflexflags=
+    cppflags2=-O3 -fPIC
+  else
+    genreflexflags=--with-methptrgetter
+    cppflags2=-Wno-pmf-conversions -O3 -fPIC
+  endif
+else
+  cppflags2=-O3 -fPIC -rdynamic
+endif
+
+ifeq ($(CINT),)
+%Dict.so: %_rflx.cpp %.cxx
+	echo $(cppflags)
+	g++ -o $@ $^ -shared -lReflex $(cppflags) $(cppflags2)
+
+%_rflx.cpp: %.h %.xml
+	$(genreflex) $< $(genreflexflags) --selection=$*.xml --rootmap=$*Dict.rootmap --rootmap-lib=$*Dict.so
+else
+%Dict.so: %_cint.cxx %.cxx
+	g++ -o $@ $^ -shared $(cppflags) $(cppflags2)
+	rlibmap -f -o $*Dict.rootmap -l $@ -c $*_LinkDef.h
+
+%_cint.cxx: %.h %_LinkDef.h
+	rootcint -f $@ -c $*.h $*_LinkDef.h
+endif
+
+ifeq ($(CINT),)
+# TODO: methptrgetter causes these tests to crash, so don't use it for now
+std_streamsDict.so: std_streams.cxx std_streams.h std_streams.xml
+	$(genreflex) std_streams.h --selection=std_streams.xml
+	g++ -o $@ std_streams_rflx.cpp std_streams.cxx -shared -lReflex $(cppflags) $(cppflags2)
+endif
+
+.PHONY: clean
+clean:
+	-rm -f $(dicts) $(subst .so,.rootmap,$(dicts)) $(wildcard *_cint.h)
diff --git a/pypy/module/cppyy/test/__init__.py b/pypy/module/cppyy/test/__init__.py
new file mode 100644
diff --git a/pypy/module/cppyy/test/advancedcpp.cxx b/pypy/module/cppyy/test/advancedcpp.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp.cxx
@@ -0,0 +1,76 @@
+#include "advancedcpp.h"
+
+
+// for testing of default arguments
+defaulter::defaulter(int a, int b, int c ) {
+   m_a = a;
+   m_b = b;
+   m_c = c;
+}
+
+
+// for esoteric inheritance testing
+a_class* create_c1() { return new c_class_1; }
+a_class* create_c2() { return new c_class_2; }
+
+int get_a( a_class& a ) { return a.m_a; }
+int get_b( b_class& b ) { return b.m_b; }
+int get_c( c_class& c ) { return c.m_c; }
+int get_d( d_class& d ) { return d.m_d; }
+
+
+// for namespace testing
+int a_ns::g_a                         = 11;
+int a_ns::b_class::s_b                = 22;
+int a_ns::b_class::c_class::s_c       = 33;
+int a_ns::d_ns::g_d                   = 44;
+int a_ns::d_ns::e_class::s_e          = 55;
+int a_ns::d_ns::e_class::f_class::s_f = 66;
+
+int a_ns::get_g_a() { return g_a; }
+int a_ns::d_ns::get_g_d() { return g_d; }
+
+
+// for template testing
+template class T1<int>;
+template class T2<T1<int> >;
+template class T3<int, double>;
+template class T3<T1<int>, T2<T1<int> > >;
+template class a_ns::T4<int>;
+template class a_ns::T4<a_ns::T4<T3<int, double> > >;
+
+
+// helpers for checking pass-by-ref
+void set_int_through_ref(int& i, int val)             { i = val; }
+int pass_int_through_const_ref(const int& i)          { return i; }
+void set_long_through_ref(long& l, long val)          { l = val; }
+long pass_long_through_const_ref(const long& l)       { return l; }
+void set_double_through_ref(double& d, double val)    { d = val; }
+double pass_double_through_const_ref(const double& d) { return d; }
+
+
+// for math conversions testing
+bool operator==(const some_comparable& c1, const some_comparable& c2 )
+{
+   return &c1 != &c2;              // the opposite of a pointer comparison
+}
+
+bool operator!=( const some_comparable& c1, const some_comparable& c2 )
+{
+   return &c1 == &c2;              // the opposite of a pointer comparison
+}
+
+
+// a couple of globals for access testing
+double my_global_double = 12.;
+double my_global_array[500];
+
+
+// for life-line and identity testing
+int some_class_with_data::some_data::s_num_data = 0;
+
+
+// for testing multiple inheritance
+multi1::~multi1() {}
+multi2::~multi2() {}
+multi::~multi() {}
diff --git a/pypy/module/cppyy/test/advancedcpp.h b/pypy/module/cppyy/test/advancedcpp.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp.h
@@ -0,0 +1,339 @@
+#include <vector>
+
+
+//===========================================================================
+class defaulter {                 // for testing of default arguments
+public:
+    defaulter(int a = 11, int b = 22, int c = 33 );
+
+public:
+    int m_a, m_b, m_c;
+};
+
+
+//===========================================================================
+class base_class {                 // for simple inheritance testing
+public:
+   base_class() { m_b = 1; m_db = 1.1; }
+   virtual ~base_class() {}
+   virtual int get_value() { return m_b; }
+   double get_base_value() { return m_db; }
+
+   virtual base_class* cycle(base_class* b) { return b; }
+   virtual base_class* clone() { return new base_class; }
+
+public:
+   int m_b;
+   double m_db;
+};
+
+class derived_class : public base_class {
+public:
+   derived_class() { m_d = 2; m_dd = 2.2;}
+   virtual int get_value() { return m_d; }
+   double get_derived_value() { return m_dd; }
+   virtual base_class* clone() { return new derived_class; }
+
+public:
+   int m_d;
+   double m_dd;
+};
+
+
+//===========================================================================
+class a_class {                    // for esoteric inheritance testing
+public:
+   a_class() { m_a = 1; m_da = 1.1; }
+   ~a_class() {}
+   virtual int get_value() = 0;
+
+public:
+   int m_a;
+   double m_da;
+};
+
+class b_class : public virtual a_class {
+public:
+   b_class() { m_b = 2; m_db = 2.2;}
+   virtual int get_value() { return m_b; }
+
+public:
+   int m_b;
+   double m_db;
+};
+
+class c_class_1 : public virtual a_class, public virtual b_class {
+public:
+   c_class_1() { m_c = 3; }
+   virtual int get_value() { return m_c; }
+
+public:
+   int m_c;
+};
+
+class c_class_2 : public virtual b_class, public virtual a_class {
+public:
+   c_class_2() { m_c = 3; }
+   virtual int get_value() { return m_c; }
+
+public:
+   int m_c;
+};
+
+typedef c_class_2 c_class;
+
+class d_class : public virtual c_class, public virtual a_class {
+public:
+   d_class() { m_d = 4; }
+   virtual int get_value() { return m_d; }
+
+public:
+   int m_d;
+};
+
+a_class* create_c1();
+a_class* create_c2();
+
+int get_a(a_class& a);
+int get_b(b_class& b);
+int get_c(c_class& c);
+int get_d(d_class& d);
+
+
+//===========================================================================
+namespace a_ns {                   // for namespace testing
+   extern int g_a;
+   int get_g_a();
+
+   struct b_class {
+      b_class() { m_b = -2; }
+      int m_b;
+      static int s_b;
+
+      struct c_class {
+         c_class() { m_c = -3; }
+         int m_c;
+         static int s_c;
+      };
+   };
+
+   namespace d_ns {
+      extern int g_d;
+      int get_g_d();
+
+      struct e_class {
+         e_class() { m_e = -5; }
+         int m_e;
+         static int s_e;
+
+         struct f_class {
+            f_class() { m_f = -6; }
+            int m_f;
+            static int s_f;
+         };
+      };
+
+   } // namespace d_ns
+
+} // namespace a_ns
+
+
+//===========================================================================
+template<typename T>               // for template testing
+class T1 {
+public:
+   T1(T t = T(1)) : m_t1(t) {}
+   T value() { return m_t1; }
+
+public:
+   T m_t1;
+};
+
+template<typename T>
+class T2 {
+public:
+   T2(T t = T(2)) : m_t2(t) {}
+   T value() { return m_t2; }
+
+public:
+   T m_t2;
+};
+
+template<typename T, typename U>
+class T3 {
+public:
+   T3(T t = T(3), U u = U(33)) : m_t3(t), m_u3(u) {}
+   T value_t() { return m_t3; }
+   U value_u() { return m_u3; }
+
+public:
+   T m_t3;
+   U m_u3;
+};
+
+namespace a_ns {
+
+   template<typename T>
+   class T4 {
+   public:
+      T4(T t = T(4)) : m_t4(t) {}
+      T value() { return m_t4; }
+
+   public:
+      T m_t4;
+   };
+
+} // namespace a_ns
+
+extern template class T1<int>;
+extern template class T2<T1<int> >;
+extern template class T3<int, double>;
+extern template class T3<T1<int>, T2<T1<int> > >;
+extern template class a_ns::T4<int>;
+extern template class a_ns::T4<a_ns::T4<T3<int, double> > >;
+
+
+//===========================================================================
+// for checking pass-by-reference of builtin types
+void set_int_through_ref(int& i, int val);
+int pass_int_through_const_ref(const int& i);
+void set_long_through_ref(long& l, long val);
+long pass_long_through_const_ref(const long& l);
+void set_double_through_ref(double& d, double val);
+double pass_double_through_const_ref(const double& d);
+
+
+//===========================================================================
+class some_abstract_class {        // to test abstract class handling
+public:
+   virtual void a_virtual_method() = 0;
+};
+
+class some_concrete_class : public some_abstract_class {
+public:
+   virtual void a_virtual_method() {}
+};
+
+
+//===========================================================================
+/*
+TODO: methptrgetter support for std::vector<>
+class ref_tester {                 // for assignment by-ref testing
+public:
+   ref_tester() : m_i(-99) {}
+   ref_tester(int i) : m_i(i) {}
+   ref_tester(const ref_tester& s) : m_i(s.m_i) {}
+   ref_tester& operator=(const ref_tester& s) {
+      if (&s != this) m_i = s.m_i;
+      return *this;
+   }
+   ~ref_tester() {}
+
+public:
+   int m_i;
+};
+
+template class std::vector< ref_tester >;
+*/
+
+
+//===========================================================================
+class some_convertible {           // for math conversions testing
+public:
+   some_convertible() : m_i(-99), m_d(-99.) {}
+
+   operator int()    { return m_i; }
+   operator long()   { return m_i; }
+   operator double() { return m_d; }
+
+public:
+   int m_i;
+   double m_d;
+};
+
+
+class some_comparable {
+};
+
+bool operator==(const some_comparable& c1, const some_comparable& c2 );
+bool operator!=( const some_comparable& c1, const some_comparable& c2 );
+
+
+//===========================================================================
+extern double my_global_double;    // a couple of globals for access testing
+extern double my_global_array[500];
+
+
+//===========================================================================
+class some_class_with_data {       // for life-line and identity testing
+public:
+   class some_data {
+   public:
+      some_data()                 { ++s_num_data; }
+      some_data(const some_data&) { ++s_num_data; }
+      ~some_data()                { --s_num_data; }
+
+      static int s_num_data;
+   };
+
+   some_class_with_data gime_copy() {
+      return *this;
+   }
+
+   const some_data& gime_data() { /* TODO: methptrgetter const support */
+      return m_data;
+   }
+
+   int m_padding;
+   some_data m_data;
+};
+
+
+//===========================================================================
+class pointer_pass {               // for testing passing of void*'s
+public:
+    long gime_address_ptr(void* obj) {
+        return (long)obj;
+    }
+
+    long gime_address_ptr_ptr(void** obj) {
+        return (long)*((long**)obj);
+    }
+
+    long gime_address_ptr_ref(void*& obj) {
+        return (long)obj;
+    }
+};
+
+
+//===========================================================================
+class multi1 {                     // for testing multiple inheritance
+public:
+    multi1(int val) : m_int(val) {}
+    virtual ~multi1();
+    int get_multi1_int() { return m_int; }
+
+private:
+    int m_int;
+};
+
+class multi2 {
+public:
+    multi2(int val) : m_int(val) {}
+    virtual ~multi2();
+    int get_multi2_int() { return m_int; }
+
+private:
+    int m_int;
+};
+
+class multi : public multi1, public multi2 {
+public:
+    multi(int val1, int val2, int val3) :
+        multi1(val1), multi2(val2), m_int(val3) {}
+    virtual ~multi();
+    int get_my_own_int() { return m_int; }
+
+private:
+    int m_int;
+};
diff --git a/pypy/module/cppyy/test/advancedcpp.xml b/pypy/module/cppyy/test/advancedcpp.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp.xml
@@ -0,0 +1,40 @@
+<lcgdict>
+
+  <class name="defaulter" />
+
+  <class name="base_class" />
+  <class name="derived_class" />
+
+  <class name="a_class" />
+  <class name="b_class" />
+  <class name="c_class" />
+  <class name="c_class_1" />
+  <class name="c_class_2" />
+  <class name="d_class" />
+
+  <function pattern="create_*" />
+  <function pattern="get_*" />
+
+  <class pattern="T1<*>" />
+  <class pattern="T2<*>" />
+  <class pattern="T3<*>" />
+
+  <namespace name="a_ns" />
+  <namespace pattern="a_ns::*" />
+  <class pattern="a_ns::*" />
+  <variable name="a_ns::g_a" />
+  <function name="a_ns::get_g_a" />
+  <variable name="a_ns::d_ns::g_d" />
+  <function name="a_ns::d_ns::get_g_d" />
+
+  <class name="some_abstract_class" />
+  <class name="some_concrete_class" />
+  <class name="some_convertible" />
+  <class name="some_class_with_data" />
+  <class name="some_class_with_data::some_data" />
+
+  <class name="pointer_pass" />
+
+  <class pattern="multi*" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/advancedcpp2.cxx b/pypy/module/cppyy/test/advancedcpp2.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp2.cxx
@@ -0,0 +1,13 @@
+#include "advancedcpp2.h"
+
+
+// for namespace testing
+int a_ns::g_g                         =  77;
+int a_ns::g_class::s_g                =  88;
+int a_ns::g_class::h_class::s_h       =  99;
+int a_ns::d_ns::g_i                   = 111;
+int a_ns::d_ns::i_class::s_i          = 222;
+int a_ns::d_ns::i_class::j_class::s_j = 333;
+
+int a_ns::get_g_g() { return g_g; }
+int a_ns::d_ns::get_g_i() { return g_i; }
diff --git a/pypy/module/cppyy/test/advancedcpp2.h b/pypy/module/cppyy/test/advancedcpp2.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp2.h
@@ -0,0 +1,36 @@
+//===========================================================================
+namespace a_ns {                   // for namespace testing
+   extern int g_g;
+   int get_g_g();
+
+   struct g_class {
+      g_class() { m_g = -7; }
+      int m_g;
+      static int s_g;
+
+      struct h_class {
+         h_class() { m_h = -8; }
+         int m_h;
+         static int s_h;
+      };
+   };
+
+   namespace d_ns {
+      extern int g_i;
+      int get_g_i();
+
+      struct i_class {
+         i_class() { m_i = -9; }
+         int m_i;
+         static int s_i;
+
+         struct j_class {
+            j_class() { m_j = -10; }
+            int m_j;
+            static int s_j;
+         };
+      };
+
+   } // namespace d_ns
+
+} // namespace a_ns
diff --git a/pypy/module/cppyy/test/advancedcpp2.xml b/pypy/module/cppyy/test/advancedcpp2.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp2.xml
@@ -0,0 +1,11 @@
+<lcgdict>
+
+  <namespace name="a_ns" />
+  <namespace pattern="a_ns::*" />
+  <class pattern="a_ns::*" />
+  <variable name="a_ns::g_g" />
+  <function name="a_ns::get_g_g" />
+  <variable name="a_ns::d_ns::g_i" />
+  <function name="a_ns::d_ns::get_g_i" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/advancedcpp2_LinkDef.h b/pypy/module/cppyy/test/advancedcpp2_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp2_LinkDef.h
@@ -0,0 +1,18 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ namespace a_ns;
+#pragma link C++ namespace a_ns::d_ns;
+#pragma link C++ struct a_ns::g_class;
+#pragma link C++ struct a_ns::g_class::h_class;
+#pragma link C++ struct a_ns::d_ns::i_class;
+#pragma link C++ struct a_ns::d_ns::i_class::j_class;
+#pragma link C++ variable a_ns::g_g;
+#pragma link C++ function a_ns::get_g_g;
+#pragma link C++ variable a_ns::d_ns::g_i;
+#pragma link C++ function a_ns::d_ns::get_g_i;
+
+#endif
diff --git a/pypy/module/cppyy/test/advancedcpp_LinkDef.h b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
@@ -0,0 +1,58 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class defaulter;
+
+#pragma link C++ class base_class;
+#pragma link C++ class derived_class;
+
+#pragma link C++ class a_class;
+#pragma link C++ class b_class;
+#pragma link C++ class c_class;
+#pragma link C++ class c_class_1;
+#pragma link C++ class c_class_2;
+#pragma link C++ class d_class;
+
+#pragma link C++ function create_c1();
+#pragma link C++ function create_c2();
+
+#pragma link C++ function get_a(a_class&);
+#pragma link C++ function get_b(b_class&);
+#pragma link C++ function get_c(c_class&);
+#pragma link C++ function get_d(d_class&);
+
+#pragma link C++ class T1<int>;
+#pragma link C++ class T2<T1<int> >;
+#pragma link C++ class T3<int, double>;
+#pragma link C++ class T3<T1<int>, T2<T1<int> > >;
+#pragma link C++ class a_ns::T4<int>;
+#pragma link C++ class a_ns::T4<T3<int,double> >;
+#pragma link C++ class a_ns::T4<a_ns::T4<T3<int, double> > >;
+
+#pragma link C++ namespace a_ns;
+#pragma link C++ namespace a_ns::d_ns;
+#pragma link C++ struct a_ns::b_class;
+#pragma link C++ struct a_ns::b_class::c_class;
+#pragma link C++ struct a_ns::d_ns::e_class;
+#pragma link C++ struct a_ns::d_ns::e_class::f_class;
+#pragma link C++ variable a_ns::g_a;
+#pragma link C++ function a_ns::get_g_a;
+#pragma link C++ variable a_ns::d_ns::g_d;
+#pragma link C++ function a_ns::d_ns::get_g_d;
+
+#pragma link C++ class some_abstract_class;
+#pragma link C++ class some_concrete_class;
+#pragma link C++ class some_convertible;
+#pragma link C++ class some_class_with_data;
+#pragma link C++ class some_class_with_data::some_data;
+
+#pragma link C++ class pointer_pass;
+
+#pragma link C++ class multi1;
+#pragma link C++ class multi2;
+#pragma link C++ class multi;
+
+#endif
diff --git a/pypy/module/cppyy/test/bench1.cxx b/pypy/module/cppyy/test/bench1.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/bench1.cxx
@@ -0,0 +1,39 @@
+#include <iostream>
+#include <iomanip>
+#include <time.h>
+#include <unistd.h>
+
+#include "example01.h"
+
+static const int NNN = 10000000;
+
+
+int cpp_loop_offset() {
+    int i = 0;
+    for ( ; i < NNN*10; ++i)
+        ;
+    return i;
+}
+
+int cpp_bench1() {
+    int i = 0;
+    example01 e;
+    for ( ; i < NNN*10; ++i)
+        e.addDataToInt(i);
+    return i;
+}
+
+
+int main() {
+
+    clock_t t1 = clock();
+    cpp_loop_offset();
+    clock_t t2 = clock();
+    cpp_bench1();
+    clock_t t3 = clock();
+
+    std::cout << std::setprecision(8)
+              << ((t3-t2) - (t2-t1))/((double)CLOCKS_PER_SEC*10.) << std::endl;
+
+    return 0;
+}
diff --git a/pypy/module/cppyy/test/bench1.py b/pypy/module/cppyy/test/bench1.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/bench1.py
@@ -0,0 +1,147 @@
+import commands, os, sys, time
+
+NNN = 10000000
+
+
+def run_bench(bench):
+    global t_loop_offset
+
+    t1 = time.time()
+    bench()
+    t2 = time.time()
+
+    t_bench = (t2-t1)-t_loop_offset
+    return bench.scale*t_bench
+
+def print_bench(name, t_bench):
+    global t_cppref
+    print ':::: %s cost: %#6.3fs (%#4.1fx)' % (name, t_bench, float(t_bench)/t_cppref)
+
+def python_loop_offset():
+    for i in range(NNN):
+        i
+    return i
+
+class PyCintexBench1(object):
+    scale = 10
+    def __init__(self):
+        import PyCintex
+        self.lib = PyCintex.gbl.gSystem.Load("./example01Dict.so")
+
+        self.cls   = PyCintex.gbl.example01
+        self.inst  = self.cls(0)
+
+    def __call__(self):
+        # note that PyCintex calls don't actually scale linearly, but worse
+        # than linear (leak or wrong filling of a cache??)
+        instance = self.inst
+        niter = NNN/self.scale
+        for i in range(niter):
+            instance.addDataToInt(i)
+        return i
+
+class PyROOTBench1(PyCintexBench1):
+    def __init__(self):
+        import ROOT
+        self.lib = ROOT.gSystem.Load("./example01Dict_cint.so")
+
+        self.cls   = ROOT.example01
+        self.inst  = self.cls(0)
+
+class CppyyInterpBench1(object):
+    scale = 1
+    def __init__(self):
+        import cppyy
+        self.lib = cppyy.load_reflection_info("./example01Dict.so")
+
+        self.cls  = cppyy._scope_byname("example01")
+        self.inst = self.cls.get_overload(self.cls.type_name).call(None, 0)
+
+    def __call__(self):
+        addDataToInt = self.cls.get_overload("addDataToInt")
+        instance = self.inst
+        for i in range(NNN):
+            addDataToInt.call(instance, i)
+        return i
+
+class CppyyInterpBench2(CppyyInterpBench1):
+    def __call__(self):
+        addDataToInt = self.cls.get_overload("overloadedAddDataToInt")
+        instance = self.inst
+        for i in range(NNN):
+            addDataToInt.call(instance, i)
+        return i
+
+class CppyyInterpBench3(CppyyInterpBench1):
+    def __call__(self):
+        addDataToInt = self.cls.get_overload("addDataToIntConstRef")
+        instance = self.inst
+        for i in range(NNN):
+            addDataToInt.call(instance, i)
+        return i
+
+class CppyyPythonBench1(object):
+    scale = 1
+    def __init__(self):
+        import cppyy
+        self.lib = cppyy.load_reflection_info("./example01Dict.so")
+
+        self.cls = cppyy.gbl.example01
+        self.inst = self.cls(0)
+
+    def __call__(self):
+        instance = self.inst
+        for i in range(NNN):
+            instance.addDataToInt(i)
+        return i
+
+
+if __name__ == '__main__':
+    python_loop_offset();
+
+    # time python loop offset
+    t1 = time.time()
+    python_loop_offset()
+    t2 = time.time()
+    t_loop_offset = t2-t1
+
+    # special case for PyCintex (run under python, not pypy-c)
+    if '--pycintex' in sys.argv:
+        cintex_bench1 = PyCintexBench1()
+        print run_bench(cintex_bench1)
+        sys.exit(0)
+
+    # special case for PyCintex (run under python, not pypy-c)
+    if '--pyroot' in sys.argv:
+        pyroot_bench1 = PyROOTBench1()
+        print run_bench(pyroot_bench1)
+        sys.exit(0)
+
+    # get C++ reference point
+    if not os.path.exists("bench1.exe") or\
+            os.stat("bench1.exe").st_mtime < os.stat("bench1.cxx").st_mtime:
+        print "rebuilding bench1.exe ... "
+        os.system( "g++ -O2 bench1.cxx example01.cxx -o bench1.exe" )
+    stat, cppref = commands.getstatusoutput("./bench1.exe")
+    t_cppref = float(cppref)
+
+    # warm-up
+    print "warming up ... "
+    interp_bench1 = CppyyInterpBench1()
+    interp_bench2 = CppyyInterpBench2()
+    interp_bench3 = CppyyInterpBench3()
+    python_bench1 = CppyyPythonBench1()
+    interp_bench1(); interp_bench2(); python_bench1()
+
+    # to allow some consistency checking
+    print "C++ reference uses %.3fs" % t_cppref
+
+    # test runs ...
+    print_bench("cppyy interp", run_bench(interp_bench1))
+    print_bench("... overload", run_bench(interp_bench2))
+    print_bench("... constref", run_bench(interp_bench3))
+    print_bench("cppyy python", run_bench(python_bench1))
+    stat, t_cintex = commands.getstatusoutput("python bench1.py --pycintex")
+    print_bench("pycintex    ", float(t_cintex))
+    #stat, t_pyroot = commands.getstatusoutput("python bench1.py --pyroot")
+    #print_bench("pyroot      ", float(t_pyroot))
diff --git a/pypy/module/cppyy/test/conftest.py b/pypy/module/cppyy/test/conftest.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/conftest.py
@@ -0,0 +1,5 @@
+import py
+
+def pytest_runtest_setup(item):
+    if py.path.local.sysfind('genreflex') is None:
+        py.test.skip("genreflex is not installed")
diff --git a/pypy/module/cppyy/test/crossing.cxx b/pypy/module/cppyy/test/crossing.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/crossing.cxx
@@ -0,0 +1,16 @@
+#include "crossing.h"
+#include <stdlib.h>
+
+extern "C" long bar_unwrap(PyObject*);
+extern "C" PyObject* bar_wrap(long);
+
+
+long crossing::A::unwrap(PyObject* pyobj)
+{
+    return bar_unwrap(pyobj);
+}
+
+PyObject* crossing::A::wrap(long l)
+{
+    return bar_wrap(l);
+}
diff --git a/pypy/module/cppyy/test/crossing.h b/pypy/module/cppyy/test/crossing.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/crossing.h
@@ -0,0 +1,12 @@
+struct _object;
+typedef _object PyObject;
+
+namespace crossing {
+
+class A {
+public:
+    long unwrap(PyObject* pyobj);
+    PyObject* wrap(long l);
+};
+
+} // namespace crossing
diff --git a/pypy/module/cppyy/test/crossing.xml b/pypy/module/cppyy/test/crossing.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/crossing.xml
@@ -0,0 +1,7 @@
+<lcgdict>
+
+  <namespace name="crossing" />
+
+  <class pattern="crossing::[A-Z]" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/crossing_LinkDef.h b/pypy/module/cppyy/test/crossing_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/crossing_LinkDef.h
@@ -0,0 +1,11 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ namespace crossing;
+
+#pragma link C++ class crossing::A;
+
+#endif
diff --git a/pypy/module/cppyy/test/datatypes.cxx b/pypy/module/cppyy/test/datatypes.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/datatypes.cxx
@@ -0,0 +1,211 @@
+#include "datatypes.h"
+
+#include <iostream>
+
+
+//===========================================================================
+cppyy_test_data::cppyy_test_data() : m_owns_arrays(false)
+{
+    m_bool   = false;
+    m_char   = 'a';
+    m_uchar  = 'c';
+    m_short  = -11;
+    m_ushort =  11u;
+    m_int    = -22;
+    m_uint   =  22u;
+    m_long   = -33l;
+    m_ulong  =  33ul;
+    m_llong  = -44ll;
+    m_ullong =  55ull;
+    m_float  = -66.f;
+    m_double = -77.;
+    m_enum   = kNothing;
+
+    m_short_array2  = new short[N];
+    m_ushort_array2 = new unsigned short[N];
+    m_int_array2    = new int[N];
+    m_uint_array2   = new unsigned int[N];
+    m_long_array2   = new long[N];
+    m_ulong_array2  = new unsigned long[N];
+
+    m_float_array2  = new float[N];
+    m_double_array2 = new double[N];
+
+    for (int i = 0; i < N; ++i) {
+        m_short_array[i]   =  -1*i;
+        m_short_array2[i]  =  -2*i;
+        m_ushort_array[i]  =   3u*i;
+        m_ushort_array2[i] =   4u*i;
+        m_int_array[i]     =  -5*i;
+        m_int_array2[i]    =  -6*i;
+        m_uint_array[i]    =   7u*i;
+        m_uint_array2[i]   =   8u*i;
+        m_long_array[i]    =  -9l*i;
+        m_long_array2[i]   = -10l*i;
+        m_ulong_array[i]   =  11ul*i;
+        m_ulong_array2[i]  =  12ul*i;
+
+        m_float_array[i]   = -13.f*i;
+        m_float_array2[i]  = -14.f*i;
+        m_double_array[i]  = -15.*i;
+        m_double_array2[i] = -16.*i;
+    }
+
+    m_owns_arrays = true;
+
+    m_pod.m_int    = 888;
+    m_pod.m_double = 3.14;
+
+    m_ppod = &m_pod;
+};
+
+cppyy_test_data::~cppyy_test_data()
+{
+    destroy_arrays();
+}
+
+void cppyy_test_data::destroy_arrays() {
+    if (m_owns_arrays == true) {
+        delete[] m_short_array2;
+        delete[] m_ushort_array2;
+        delete[] m_int_array2;
+        delete[] m_uint_array2;
+        delete[] m_long_array2;
+        delete[] m_ulong_array2;
+
+        delete[] m_float_array2;
+        delete[] m_double_array2;
+
+        m_owns_arrays = false;
+    }
+}
+
+//- getters -----------------------------------------------------------------
+bool           cppyy_test_data::get_bool()   { return m_bool; }
+char           cppyy_test_data::get_char()   { return m_char; }
+unsigned char  cppyy_test_data::get_uchar()  { return m_uchar; }
+short          cppyy_test_data::get_short()  { return m_short; }
+unsigned short cppyy_test_data::get_ushort() { return m_ushort; }
+int            cppyy_test_data::get_int()    { return m_int; }
+unsigned int   cppyy_test_data::get_uint()   { return m_uint; }
+long           cppyy_test_data::get_long()   { return m_long; }
+unsigned long  cppyy_test_data::get_ulong()  { return m_ulong; }
+long long      cppyy_test_data::get_llong()  { return m_llong; }
+unsigned long long cppyy_test_data::get_ullong()  { return m_ullong; }
+float          cppyy_test_data::get_float()  { return m_float; }
+double         cppyy_test_data::get_double() { return m_double; }
+cppyy_test_data::what cppyy_test_data::get_enum() { return m_enum; }
+
+short*          cppyy_test_data::get_short_array()   { return m_short_array; }
+short*          cppyy_test_data::get_short_array2()  { return m_short_array2; }
+unsigned short* cppyy_test_data::get_ushort_array()  { return m_ushort_array; }
+unsigned short* cppyy_test_data::get_ushort_array2() { return m_ushort_array2; }
+int*            cppyy_test_data::get_int_array()     { return m_int_array; }
+int*            cppyy_test_data::get_int_array2()    { return m_int_array2; }
+unsigned int*   cppyy_test_data::get_uint_array()    { return m_uint_array; }
+unsigned int*   cppyy_test_data::get_uint_array2()   { return m_uint_array2; }
+long*           cppyy_test_data::get_long_array()    { return m_long_array; }
+long*           cppyy_test_data::get_long_array2()   { return m_long_array2; }
+unsigned long*  cppyy_test_data::get_ulong_array()   { return m_ulong_array; }
+unsigned long*  cppyy_test_data::get_ulong_array2()  { return m_ulong_array2; }
+
+float*  cppyy_test_data::get_float_array()   { return m_float_array; }
+float*  cppyy_test_data::get_float_array2()  { return m_float_array2; }
+double* cppyy_test_data::get_double_array()  { return m_double_array; }
+double* cppyy_test_data::get_double_array2() { return m_double_array2; }
+
+cppyy_test_pod cppyy_test_data::get_pod_val() { return m_pod; }
+cppyy_test_pod* cppyy_test_data::get_pod_ptr() { return &m_pod; }
+cppyy_test_pod& cppyy_test_data::get_pod_ref() { return m_pod; }
+cppyy_test_pod*& cppyy_test_data::get_pod_ptrref() { return m_ppod; }
+
+//- setters -----------------------------------------------------------------
+void cppyy_test_data::set_bool(bool b)                       { m_bool   = b; }
+void cppyy_test_data::set_char(char c)                       { m_char   = c; }
+void cppyy_test_data::set_uchar(unsigned char uc)            { m_uchar  = uc; }
+void cppyy_test_data::set_short(short s)                     { m_short  = s; }
+void cppyy_test_data::set_short_c(const short& s)            { m_short  = s; }
+void cppyy_test_data::set_ushort(unsigned short us)          { m_ushort = us; }
+void cppyy_test_data::set_ushort_c(const unsigned short& us) { m_ushort = us; }
+void cppyy_test_data::set_int(int i)                         { m_int    = i; }
+void cppyy_test_data::set_int_c(const int& i)                { m_int    = i; }
+void cppyy_test_data::set_uint(unsigned int ui)              { m_uint   = ui; }
+void cppyy_test_data::set_uint_c(const unsigned int& ui)     { m_uint   = ui; }
+void cppyy_test_data::set_long(long l)                       { m_long   = l; }
+void cppyy_test_data::set_long_c(const long& l)              { m_long   = l; }
+void cppyy_test_data::set_ulong(unsigned long ul)            { m_ulong  = ul; }
+void cppyy_test_data::set_ulong_c(const unsigned long& ul)   { m_ulong  = ul; }
+void cppyy_test_data::set_llong(long long ll)                { m_llong  = ll; }
+void cppyy_test_data::set_llong_c(const long long& ll)       { m_llong  = ll; }
+void cppyy_test_data::set_ullong(unsigned long long ull)     { m_ullong  = ull; }
+void cppyy_test_data::set_ullong_c(const unsigned long long& ull) { m_ullong  = ull; }
+void cppyy_test_data::set_float(float f)                     { m_float  = f; }
+void cppyy_test_data::set_float_c(const float& f)            { m_float  = f; }
+void cppyy_test_data::set_double(double d)                   { m_double = d; }
+void cppyy_test_data::set_double_c(const double& d)          { m_double = d; }
+void cppyy_test_data::set_enum(what w)                       { m_enum   = w; }
+
+void cppyy_test_data::set_pod_val(cppyy_test_pod p)            { m_pod = p; }
+void cppyy_test_data::set_pod_ptr_in(cppyy_test_pod* pp)       { m_pod = *pp; }
+void cppyy_test_data::set_pod_ptr_out(cppyy_test_pod* pp)      { *pp = m_pod; }
+void cppyy_test_data::set_pod_ref(const cppyy_test_pod& rp)    { m_pod = rp; }
+void cppyy_test_data::set_pod_ptrptr_in(cppyy_test_pod** ppp)  { m_pod = **ppp; }
+void cppyy_test_data::set_pod_void_ptrptr_in(void** pp)        { m_pod = **((cppyy_test_pod**)pp); }
+void cppyy_test_data::set_pod_ptrptr_out(cppyy_test_pod** ppp) { *ppp = &m_pod; }
+void cppyy_test_data::set_pod_void_ptrptr_out(void** pp)       { *((cppyy_test_pod**)pp) = &m_pod; }
+
+char                cppyy_test_data::s_char   = 's';
+unsigned char       cppyy_test_data::s_uchar  = 'u';
+short               cppyy_test_data::s_short  = -101;
+unsigned short      cppyy_test_data::s_ushort =  255u;
+int                 cppyy_test_data::s_int    = -202;
+unsigned int        cppyy_test_data::s_uint   =  202u;
+long                cppyy_test_data::s_long   = -303l;
+unsigned long       cppyy_test_data::s_ulong  =  303ul;
+long long           cppyy_test_data::s_llong  = -404ll;
+unsigned long long  cppyy_test_data::s_ullong =  505ull;
+float               cppyy_test_data::s_float  = -606.f;
+double              cppyy_test_data::s_double = -707.;
+cppyy_test_data::what  cppyy_test_data::s_enum = cppyy_test_data::kNothing;
+
+
+//= global functions ========================================================
+long get_pod_address(cppyy_test_data& c)
+{
+    return (long)&c.m_pod;
+}
+
+long get_int_address(cppyy_test_data& c)
+{
+    return (long)&c.m_pod.m_int;
+}
+
+long get_double_address(cppyy_test_data& c)
+{
+    return (long)&c.m_pod.m_double;
+}
+
+//= global variables/pointers ===============================================
+int g_int = 42;
+
+void set_global_int(int i) {
+   g_int = i;
+}
+
+int get_global_int() {
+   return g_int;
+}
+
+cppyy_test_pod* g_pod = (cppyy_test_pod*)0;
+
+bool is_global_pod(cppyy_test_pod* t) {
+   return t == g_pod;
+}
+
+void set_global_pod(cppyy_test_pod* t) {
+   g_pod = t;
+}
+
+cppyy_test_pod* get_global_pod() {
+   return g_pod;
+}
diff --git a/pypy/module/cppyy/test/datatypes.h b/pypy/module/cppyy/test/datatypes.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/datatypes.h
@@ -0,0 +1,171 @@
+const int N = 5;
+
+
+//===========================================================================
+struct cppyy_test_pod {
+   int    m_int;
+   double m_double;
+};
+
+
+//===========================================================================
+class cppyy_test_data {
+public:
+    cppyy_test_data();
+    ~cppyy_test_data();
+
+// special cases
+   enum what { kNothing=6, kSomething=111, kLots=42 };
+
+// helper
+    void destroy_arrays();
+
+// getters
+    bool                 get_bool();
+    char                 get_char();
+    unsigned char        get_uchar();
+    short                get_short();
+    unsigned short       get_ushort();
+    int                  get_int();
+    unsigned int         get_uint();
+    long                 get_long();
+    unsigned long        get_ulong();
+    long long            get_llong();
+    unsigned long long   get_ullong();
+    float                get_float();
+    double               get_double();
+    what                 get_enum();
+
+    short*          get_short_array();
+    short*          get_short_array2();
+    unsigned short* get_ushort_array();
+    unsigned short* get_ushort_array2();
+    int*            get_int_array();
+    int*            get_int_array2();
+    unsigned int*   get_uint_array();
+    unsigned int*   get_uint_array2();
+    long*           get_long_array();
+    long*           get_long_array2();
+    unsigned long*  get_ulong_array();
+    unsigned long*  get_ulong_array2();
+
+    float*  get_float_array();
+    float*  get_float_array2();
+    double* get_double_array();
+    double* get_double_array2();
+
+    cppyy_test_pod get_pod_val();
+    cppyy_test_pod* get_pod_ptr();
+    cppyy_test_pod& get_pod_ref();
+    cppyy_test_pod*& get_pod_ptrref();
+
+// setters
+    void set_bool(bool b);
+    void set_char(char c);
+    void set_uchar(unsigned char uc);
+    void set_short(short s);
+    void set_short_c(const short& s);
+    void set_ushort(unsigned short us);
+    void set_ushort_c(const unsigned short& us);
+    void set_int(int i);
+    void set_int_c(const int& i);
+    void set_uint(unsigned int ui);
+    void set_uint_c(const unsigned int& ui);
+    void set_long(long l);
+    void set_long_c(const long& l);
+    void set_llong(long long ll);
+    void set_llong_c(const long long& ll);
+    void set_ulong(unsigned long ul);
+    void set_ulong_c(const unsigned long& ul);
+    void set_ullong(unsigned long long ll);
+    void set_ullong_c(const unsigned long long& ll);
+    void set_float(float f);
+    void set_float_c(const float& f);
+    void set_double(double d);
+    void set_double_c(const double& d);
+    void set_enum(what w);
+
+    void set_pod_val(cppyy_test_pod);
+    void set_pod_ptr_in(cppyy_test_pod*);
+    void set_pod_ptr_out(cppyy_test_pod*);
+    void set_pod_ref(const cppyy_test_pod&);
+    void set_pod_ptrptr_in(cppyy_test_pod**);
+    void set_pod_void_ptrptr_in(void**);
+    void set_pod_ptrptr_out(cppyy_test_pod**);
+    void set_pod_void_ptrptr_out(void**);
+
+public:
+// basic types
+    bool                 m_bool;
+    char                 m_char;
+    unsigned char        m_uchar;
+    short                m_short;
+    unsigned short       m_ushort;
+    int                  m_int;
+    unsigned int         m_uint;
+    long                 m_long;
+    unsigned long        m_ulong;
+    long long            m_llong;
+    unsigned long long   m_ullong;
+    float                m_float;
+    double               m_double;
+    what                 m_enum;
+
+// array types
+    short           m_short_array[N];
+    short*          m_short_array2;
+    unsigned short  m_ushort_array[N];
+    unsigned short* m_ushort_array2;
+    int             m_int_array[N];
+    int*            m_int_array2;
+    unsigned int    m_uint_array[N];
+    unsigned int*   m_uint_array2;
+    long            m_long_array[N];
+    long*           m_long_array2;
+    unsigned long   m_ulong_array[N];
+    unsigned long*  m_ulong_array2;
+ 
+    float   m_float_array[N];
+    float*  m_float_array2;
+    double  m_double_array[N];
+    double* m_double_array2;
+
+// object types
+    cppyy_test_pod m_pod;
+    cppyy_test_pod* m_ppod;
+
+public:
+    static char                    s_char;
+    static unsigned char           s_uchar;
+    static short                   s_short;
+    static unsigned short          s_ushort;
+    static int                     s_int;
+    static unsigned int            s_uint;
+    static long                    s_long;
+    static unsigned long           s_ulong;
+    static long long               s_llong;
+    static unsigned long long      s_ullong;
+    static float                   s_float;
+    static double                  s_double;
+    static what                    s_enum;
+
+private:
+    bool m_owns_arrays;
+};
+
+
+//= global functions ========================================================
+long get_pod_address(cppyy_test_data& c);
+long get_int_address(cppyy_test_data& c);
+long get_double_address(cppyy_test_data& c);
+
+
+//= global variables/pointers ===============================================
+extern int g_int;
+void set_global_int(int i);
+int get_global_int();
+
+extern cppyy_test_pod* g_pod;
+bool is_global_pod(cppyy_test_pod* t);
+void set_global_pod(cppyy_test_pod* t);
+cppyy_test_pod* get_global_pod();
diff --git a/pypy/module/cppyy/test/datatypes.xml b/pypy/module/cppyy/test/datatypes.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/datatypes.xml
@@ -0,0 +1,14 @@
+<lcgdict>
+
+  <class pattern="cppyy_test_*" />
+
+  <function pattern="get_*" />
+  <function pattern="set_*" />
+  <function pattern="is_*" />
+
+  <variable name="N" />
+
+  <variable name="g_int" />
+  <variable name="g_pod" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/datatypes_LinkDef.h b/pypy/module/cppyy/test/datatypes_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/datatypes_LinkDef.h
@@ -0,0 +1,24 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ struct cppyy_test_pod;
+#pragma link C++ class cppyy_test_data;
+
+#pragma link C++ function get_pod_address(cppyy_test_data&);
+#pragma link C++ function get_int_address(cppyy_test_data&);
+#pragma link C++ function get_double_address(cppyy_test_data&);
+#pragma link C++ function set_global_int(int);
+#pragma link C++ function get_global_int();
+
+#pragma link C++ function is_global_pod(cppyy_test_pod*);
+#pragma link C++ function set_global_pod(cppyy_test_pod*);
+#pragma link C++ function get_global_pod();
+
+#pragma link C++ global N;
+#pragma link C++ global g_int;
+#pragma link C++ global g_pod;
+
+#endif
diff --git a/pypy/module/cppyy/test/example01.cxx b/pypy/module/cppyy/test/example01.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/example01.cxx
@@ -0,0 +1,209 @@
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <stdlib.h>
+#include <string.h>
+
+#include "example01.h"
+
+//===========================================================================
+payload::payload(double d) : m_data(d) {
+    count++;
+}
+payload::payload(const payload& p) : m_data(p.m_data) {
+    count++;
+}
+payload& payload::operator=(const payload& p) {
+    if (this != &p) {
+        m_data = p.m_data;
+    }
+    return *this;
+}
+payload::~payload() {
+    count--;
+}
+
+double payload::getData() { return m_data; }
+void payload::setData(double d) { m_data = d; }
+
+// class-level data
+int payload::count = 0;
+
+
+//===========================================================================
+example01::example01() : m_somedata(-99) {
+    count++;
+}
+example01::example01(int a) : m_somedata(a) {
+    count++;
+}
+example01::example01(const example01& e) : m_somedata(e.m_somedata) {
+    count++;
+}
+example01& example01::operator=(const example01& e) {
+    if (this != &e) {
+        m_somedata = e.m_somedata;
+    }
+    return *this;
+}
+example01::~example01() {
+    count--;
+}
+
+// class-level methods
+int example01::staticAddOneToInt(int a) {
+    return a + 1;
+}
+int example01::staticAddOneToInt(int a, int b) {
+    return a + b + 1;
+}
+double example01::staticAddToDouble(double a) {
+    return a + 0.01;
+}
+int example01::staticAtoi(const char* str) {
+    return ::atoi(str);
+}
+char* example01::staticStrcpy(const char* strin) {
+    char* strout = (char*)malloc(::strlen(strin)+1);
+    ::strcpy(strout, strin);
+    return strout;
+}
+void example01::staticSetPayload(payload* p, double d) {
+    p->setData(d);
+}
+
+payload* example01::staticCyclePayload(payload* p, double d) {
+    staticSetPayload(p, d);
+    return p;
+}
+
+payload example01::staticCopyCyclePayload(payload* p, double d) {
+    staticSetPayload(p, d);
+    return *p;
+}
+
+int example01::getCount() {
+    return count;
+}
+
+void example01::setCount(int value) {
+    count = value;
+}
+
+// instance methods
+int example01::addDataToInt(int a) {
+    return m_somedata + a;
+}
+
+int example01::addDataToIntConstRef(const int& a) {
+    return m_somedata + a;
+}
+
+int example01::overloadedAddDataToInt(int a, int b) {
+   return m_somedata + a + b;
+}
+
+int example01::overloadedAddDataToInt(int a) {
+   return m_somedata + a;
+}
+
+int example01::overloadedAddDataToInt(int a, int b, int c) {
+   return m_somedata + a + b + c;
+}
+
+double example01::addDataToDouble(double a) {
+    return m_somedata + a;
+}
+
+int example01::addDataToAtoi(const char* str) {
+    return ::atoi(str) + m_somedata;
+}   
+
+char* example01::addToStringValue(const char* str) {
+    int out = ::atoi(str) + m_somedata;
+    std::ostringstream ss;
+    ss << out << std::ends;
+    std::string result = ss.str();
+    char* cresult = (char*)malloc(result.size()+1);
+    ::strcpy(cresult, result.c_str());
+    return cresult;
+}
+
+void example01::setPayload(payload* p) {
+    p->setData(m_somedata);
+}
+
+payload* example01::cyclePayload(payload* p) {
+    setPayload(p);
+    return p;
+}
+
+payload example01::copyCyclePayload(payload* p) {
+    setPayload(p);
+    return *p;
+}
+
+// class-level data
+int example01::count = 0;
+
+
+// global
+int globalAddOneToInt(int a) {
+   return a + 1;
+}
+
+int ns_example01::globalAddOneToInt(int a) {
+   return ::globalAddOneToInt(a);
+}
+
+
+// argument passing
+#define typeValueImp(itype, tname)                                            \
+itype ArgPasser::tname##Value(itype arg0, int argn, itype arg1, itype arg2)   \
+{                                                                             \
+   switch (argn) {                                                            \
+   case 0:                                                                    \
+      return arg0;                                                            \
+   case 1:                                                                    \
+      return arg1;                                                            \
+   case 2:                                                                    \
+      return arg2;                                                            \
+   default:                                                                   \
+      break;                                                                  \
+   }                                                                          \
+                                                                              \
+   return (itype)-1;                                                          \
+}
+
+typeValueImp(short, short)
+typeValueImp(unsigned short, ushort)
+typeValueImp(int, int)
+typeValueImp(unsigned int, uint)
+typeValueImp(long, long)
+typeValueImp(unsigned long, ulong)
+
+typeValueImp(float, float)
+typeValueImp(double, double)
+
+std::string ArgPasser::stringValue(std::string arg0, int argn, std::string arg1)
+{
+   switch (argn) {


More information about the pypy-commit mailing list