[pypy-commit] pypy stdlib-2.7.3: hg merge default

amauryfa noreply at buildbot.pypy.org
Sat Jul 7 23:01:41 CEST 2012


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: stdlib-2.7.3
Changeset: r55981:9b4cc192bc8a
Date: 2012-07-07 22:05 +0200
http://bitbucket.org/pypy/pypy/changeset/9b4cc192bc8a/

Log:	hg merge default

diff too long, truncating to 10000 out of 13047 lines

diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -20,6 +20,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/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/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
@@ -2747,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:
diff --git a/pypy/config/test/test_pypyoption.py b/pypy/config/test/test_pypyoption.py
--- a/pypy/config/test/test_pypyoption.py
+++ b/pypy/config/test/test_pypyoption.py
@@ -71,7 +71,7 @@
         c = Config(descr)
         for path in c.getpaths(include_groups=True):
             fn = prefix + "." + path + ".txt"
-            yield check_file_exists, fn
+            yield fn, check_file_exists, fn
 
 def test__ffi_opt():
     config = get_pypy_config(translating=True)
diff --git a/pypy/doc/config/objspace.usemodules.cppyy.txt b/pypy/doc/config/objspace.usemodules.cppyy.txt
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/objspace.usemodules.cppyy.txt
@@ -0,0 +1,1 @@
+Use the 'cppyy' module
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,7 +73,8 @@
 .. _`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.
+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, or the
 ``root-config`` utility must be accessible through ``PATH`` (e.g. by adding
@@ -82,16 +85,21 @@
 
     $ 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
@@ -368,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.
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/image/agile-talk.jpg b/pypy/doc/image/agile-talk.jpg
deleted file mode 100644
Binary file pypy/doc/image/agile-talk.jpg has changed
diff --git a/pypy/doc/image/architecture-session.jpg b/pypy/doc/image/architecture-session.jpg
deleted file mode 100644
Binary file pypy/doc/image/architecture-session.jpg has changed
diff --git a/pypy/doc/image/bram.jpg b/pypy/doc/image/bram.jpg
deleted file mode 100644
Binary file pypy/doc/image/bram.jpg has changed
diff --git a/pypy/doc/image/coding-discussion.jpg b/pypy/doc/image/coding-discussion.jpg
deleted file mode 100644
Binary file pypy/doc/image/coding-discussion.jpg has changed
diff --git a/pypy/doc/image/guido.jpg b/pypy/doc/image/guido.jpg
deleted file mode 100644
Binary file pypy/doc/image/guido.jpg has changed
diff --git a/pypy/doc/image/interview-bobippolito.jpg b/pypy/doc/image/interview-bobippolito.jpg
deleted file mode 100644
Binary file pypy/doc/image/interview-bobippolito.jpg has changed
diff --git a/pypy/doc/image/interview-timpeters.jpg b/pypy/doc/image/interview-timpeters.jpg
deleted file mode 100644
Binary file pypy/doc/image/interview-timpeters.jpg has changed
diff --git a/pypy/doc/image/introductory-student-talk.jpg b/pypy/doc/image/introductory-student-talk.jpg
deleted file mode 100644
Binary file pypy/doc/image/introductory-student-talk.jpg has changed
diff --git a/pypy/doc/image/introductory-talk-pycon.jpg b/pypy/doc/image/introductory-talk-pycon.jpg
deleted file mode 100644
Binary file pypy/doc/image/introductory-talk-pycon.jpg has changed
diff --git a/pypy/doc/image/ironpython.jpg b/pypy/doc/image/ironpython.jpg
deleted file mode 100644
Binary file pypy/doc/image/ironpython.jpg has changed
diff --git a/pypy/doc/image/mallorca-trailer.jpg b/pypy/doc/image/mallorca-trailer.jpg
deleted file mode 100644
Binary file pypy/doc/image/mallorca-trailer.jpg has changed
diff --git a/pypy/doc/image/pycon-trailer.jpg b/pypy/doc/image/pycon-trailer.jpg
deleted file mode 100644
Binary file pypy/doc/image/pycon-trailer.jpg has changed
diff --git a/pypy/doc/image/sprint-tutorial.jpg b/pypy/doc/image/sprint-tutorial.jpg
deleted file mode 100644
Binary file pypy/doc/image/sprint-tutorial.jpg has changed
diff --git a/pypy/doc/release-1.9.0.rst b/pypy/doc/release-1.9.0.rst
--- a/pypy/doc/release-1.9.0.rst
+++ b/pypy/doc/release-1.9.0.rst
@@ -102,8 +102,8 @@
 JitViewer
 =========
 
-There is a corresponding 1.9 release of JitViewer which is guaranteed to work
-with PyPy 1.9. See the `JitViewer docs`_ for details.
+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
 
diff --git a/pypy/doc/video-index.rst b/pypy/doc/video-index.rst
--- a/pypy/doc/video-index.rst
+++ b/pypy/doc/video-index.rst
@@ -2,39 +2,11 @@
 PyPy video documentation 
 =========================
 
-Requirements to download and view
----------------------------------
-
-In order to download the videos you need to point a
-BitTorrent client at the torrent files provided below. 
-We do not provide any other download method at this
-time.  Please get a BitTorrent client (such as bittorrent). 
-For a list of clients please 
-see http://en.wikipedia.org/wiki/Category:Free_BitTorrent_clients or 
-http://en.wikipedia.org/wiki/Comparison_of_BitTorrent_clients. 
-For more information about Bittorrent see 
-http://en.wikipedia.org/wiki/Bittorrent.
-
-In order to view the downloaded movies you need to 
-have a video player that supports DivX AVI files (DivX 5, mp3 audio)
-such as `mplayer`_, `xine`_, `vlc`_ or the windows media player.
-
-.. _`mplayer`: http://www.mplayerhq.hu/design7/dload.html
-.. _`xine`: http://www.xine-project.org
-.. _`vlc`: http://www.videolan.org/vlc/
-
-You can find the necessary codecs in the ffdshow-library:
-http://sourceforge.net/projects/ffdshow/
-
-or use the original divx codec (for Windows):
-http://www.divx.com/software/divx-plus
-
-
 Copyrights and Licensing 
 ----------------------------
 
-The following videos are copyrighted by merlinux gmbh and 
-published under the Creative Commons Attribution License 2.0 Germany: http://creativecommons.org/licenses/by/2.0/de/
+The following videos are copyrighted by merlinux gmbh and available on
+YouTube.
 
 If you need another license, don't hesitate to contact us. 
 
@@ -42,255 +14,202 @@
 Trailer: PyPy at the PyCon 2006
 -------------------------------
 
-130mb: http://buildbot.pypy.org/misc/torrent/pycon-trailer.avi.torrent
+This trailer shows the PyPy team at the PyCon 2006, a behind-the-scenes at
+sprints, talks and everywhere else.
 
-71mb: http://buildbot.pypy.org/misc/torrent/pycon-trailer-medium.avi.torrent
+.. raw:: html
 
-50mb: http://buildbot.pypy.org/misc/torrent/pycon-trailer-320x240.avi.torrent
-
-.. image:: image/pycon-trailer.jpg
-   :scale: 100
-   :alt: Trailer PyPy at PyCon
-   :align: left
-
-This trailer shows the PyPy team at the PyCon 2006, a behind-the-scenes at sprints, talks and everywhere else.
-
-PAL, 9 min, DivX AVI
-
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/WfGszrRUdtc?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Interview with Tim Peters
 -------------------------
 
-440mb: http://buildbot.pypy.org/misc/torrent/interview-timpeters-v2.avi.torrent
+Interview with CPython core developer Tim Peters at PyCon 2006, Dallas,
+US. (2006-03-02)
 
-138mb: http://buildbot.pypy.org/misc/torrent/interview-timpeters-320x240.avi.torrent
+Tim Peters, a longtime CPython core developer talks about how he got into
+Python, what he thinks about the PyPy project and why he thinks it would have
+never been possible in the US.
 
-.. image:: image/interview-timpeters.jpg
-   :scale: 100
-   :alt: Interview with Tim Peters
-   :align: left
+.. raw:: html
 
-Interview with CPython core developer Tim Peters at PyCon 2006, Dallas, US. (2006-03-02)
-
-PAL, 23 min, DivX AVI
-
-Tim Peters, a longtime CPython core developer talks about how he got into Python, what he thinks about the PyPy project and why he thinks it would have never been possible in the US.
-
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/1wAOy88WxmY?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Interview with Bob Ippolito
 ---------------------------
 
-155mb: http://buildbot.pypy.org/misc/torrent/interview-bobippolito-v2.avi.torrent
+What do you think about PyPy? Interview with American software developer Bob
+Ippolito at PyCon 2006, Dallas, US. (2006-03-01)
 
-50mb: http://buildbot.pypy.org/misc/torrent/interview-bobippolito-320x240.avi.torrent
+Bob Ippolito is an Open Source software developer from San Francisco and has
+been to two PyPy sprints. In this interview he is giving his opinion on the
+project.
 
-.. image:: image/interview-bobippolito.jpg
-   :scale: 100
-   :alt: Interview with Bob Ippolito
-   :align: left
+.. raw:: html
 
-What do you think about PyPy? Interview with American software developer Bob Ippolito at tPyCon 2006, Dallas, US. (2006-03-01)
-
-PAL 8 min, DivX AVI
-
-Bob Ippolito is an Open Source software developer from San Francisco and has been to two PyPy sprints. In this interview he is giving his opinion on the project.
-
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/c5rq4Q03zgg?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Introductory talk on PyPy
 -------------------------
 
-430mb: http://buildbot.pypy.org/misc/torrent/introductory-talk-pycon-v1.avi.torrent
-
-166mb: http://buildbot.pypy.org/misc/torrent/introductory-talk-pycon-320x240.avi.torrent
-
-.. image:: image/introductory-talk-pycon.jpg
-   :scale: 100
-   :alt: Introductory talk at PyCon 2006
-   :align: left
-
-This introductory talk is given by core developers Michael Hudson and Christian Tismer at PyCon 2006, Dallas, US. (2006-02-26)
-
-PAL, 28 min, divx AVI
+This introductory talk is given by core developers Michael Hudson and
+Christian Tismer at PyCon 2006, Dallas, US. (2006-02-26)
 
 Michael Hudson talks about the basic building blocks of Python, the currently
 available back-ends, and the status of PyPy in general. Christian Tismer takes
-over to explain how co-routines can be used to implement things like
-Stackless and Greenlets in PyPy.
+over to explain how co-routines can be used to implement things like Stackless
+and Greenlets in PyPy.
 
+.. raw:: html
+
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/AWUhXW2pLDE?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Talk on Agile Open Source Methods in the PyPy project
 -----------------------------------------------------
 
-395mb: http://buildbot.pypy.org/misc/torrent/agile-talk-v1.avi.torrent
-
-153mb: http://buildbot.pypy.org/misc/torrent/agile-talk-320x240.avi.torrent
-
-.. image:: image/agile-talk.jpg
-   :scale: 100
-   :alt: Agile talk
-   :align: left
-
-Core developer Holger Krekel and project manager Beatrice During are giving a talk on the agile open source methods used in the PyPy project at PyCon 2006, Dallas, US. (2006-02-26)
-
-PAL, 26 min, divx AVI
+Core developer Holger Krekel and project manager Beatrice During are giving a
+talk on the agile open source methods used in the PyPy project at PyCon 2006,
+Dallas, US. (2006-02-26)
 
 Holger Krekel explains more about the goals and history of PyPy, and the
 structure and organization behind it. Bea During describes the intricacies of
 driving a distributed community in an agile way, and how to combine that with
 the formalities required for EU funding.
 
+.. raw:: html
+
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/ed-zAxZtGlY?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 PyPy Architecture session
 -------------------------
 
-744mb: http://buildbot.pypy.org/misc/torrent/architecture-session-v1.avi.torrent
-
-288mb: http://buildbot.pypy.org/misc/torrent/architecture-session-320x240.avi.torrent
-
-.. image:: image/architecture-session.jpg
-   :scale: 100
-   :alt: Architecture session
-   :align: left
-
-This architecture session is given by core developers Holger Krekel and Armin Rigo at PyCon 2006, Dallas, US. (2006-02-26)
-
-PAL, 48 min, divx AVI
+This architecture session is given by core developers Holger Krekel and Armin
+Rigo at PyCon 2006, Dallas, US. (2006-02-26)
 
 Holger Krekel and Armin Rigo talk about the basic implementation,
-implementation level aspects and the RPython translation toolchain. This
-talk also gives an insight into how a developer works with these tools on
-a daily basis, and pays special attention to flow graphs.
+implementation level aspects and the RPython translation toolchain. This talk
+also gives an insight into how a developer works with these tools on a daily
+basis, and pays special attention to flow graphs.
 
+.. raw:: html
+
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/7opXGaQUUA4?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Sprint tutorial
 ---------------
 
-680mb: http://buildbot.pypy.org/misc/torrent/sprint-tutorial-v2.avi.torrent
+Sprint tutorial by core developer Michael Hudson at PyCon 2006, Dallas,
+US. (2006-02-27)
 
-263mb: http://buildbot.pypy.org/misc/torrent/sprint-tutorial-320x240.avi.torrent
+Michael Hudson gives an in-depth, very technical introduction to a PyPy
+sprint. The film provides a detailed and hands-on overview about the
+architecture of PyPy, especially the RPython translation toolchain.
 
-.. image:: image/sprint-tutorial.jpg
-   :scale: 100
-   :alt: Sprint Tutorial
-   :align: left
+.. raw:: html
 
-Sprint tutorial by core developer Michael Hudson at PyCon 2006, Dallas, US. (2006-02-27)
-
-PAL, 44 min, divx AVI
-
-Michael Hudson gives an in-depth, very technical introduction to a PyPy sprint. The film provides a detailed and hands-on overview about the architecture of PyPy, especially the RPython translation toolchain.
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/1YV7J74xrMI?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Scripting .NET with IronPython by Jim Hugunin
 ---------------------------------------------
 
-372mb: http://buildbot.pypy.org/misc/torrent/ironpython-talk-v2.avi.torrent
+Talk by Jim Hugunin (Microsoft) on the IronPython implementation on the .NET
+framework at the PyCon 2006, Dallas, US.
 
-270mb: http://buildbot.pypy.org/misc/torrent/ironpython-talk-320x240.avi.torrent
+Jim Hugunin talks about regression tests, the code generation and the object
+layout, the new-style instance and gives a CLS interop demo.
 
-.. image:: image/ironpython.jpg
-   :scale: 100
-   :alt: Jim Hugunin on IronPython
-   :align: left
+.. raw:: html
 
-Talk by Jim Hugunin (Microsoft) on the IronPython implementation on the .NET framework at this years PyCon, Dallas, US.
-
-PAL, 44 min, DivX AVI
-
-Jim Hugunin talks about regression tests, the code generation and the object layout, the new-style instance and gives a CLS interop demo.
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/bq9ZGN3-o80?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Bram Cohen, founder and developer of BitTorrent
 -----------------------------------------------
 
-509mb: http://buildbot.pypy.org/misc/torrent/bram-cohen-interview-v1.avi.torrent
+Bram Cohen is interviewed by Steve Holden at the PyCon 2006, Dallas, US.
 
-370mb: http://buildbot.pypy.org/misc/torrent/bram-cohen-interview-320x240.avi.torrent
+.. raw:: html
 
-.. image:: image/bram.jpg
-   :scale: 100
-   :alt: Bram Cohen on BitTorrent
-   :align: left
-
-Bram Cohen is interviewed by Steve Holden at this years PyCon, Dallas, US.
-
-PAL, 60 min, DivX AVI
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/EopmJWrLmWI?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Keynote speech by Guido van Rossum on the new Python 2.5 features
 -----------------------------------------------------------------
 
-695mb: http://buildbot.pypy.org/misc/torrent/keynote-speech_guido-van-rossum_v1.avi.torrent
+Guido van Rossum explains the new Python 2.5 features at the PyCon 2006,
+Dallas, US.
 
-430mb: http://buildbot.pypy.org/misc/torrent/keynote-speech_guido-van-rossum_320x240.avi.torrent
+.. raw:: html
 
-.. image:: image/guido.jpg
-   :scale: 100
-   :alt: Guido van Rossum on Python 2.5
-   :align: left
-
-Guido van Rossum explains the new Python 2.5 features at this years PyCon, Dallas, US.
-
-PAL, 70 min, DivX AVI
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/RR2sX8tFGsI?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Trailer: PyPy sprint at the University of Palma de Mallorca
 -----------------------------------------------------------
 
-166mb: http://buildbot.pypy.org/misc/torrent/mallorca-trailer-v1.avi.torrent
+This trailer shows the PyPy team at the sprint in Mallorca, a
+behind-the-scenes of a typical PyPy coding sprint and talk as well as
+everything else.
 
-88mb: http://buildbot.pypy.org/misc/torrent/mallorca-trailer-medium.avi.torrent
+.. raw:: html
 
-64mb: http://buildbot.pypy.org/misc/torrent/mallorca-trailer-320x240.avi.torrent
-
-.. image:: image/mallorca-trailer.jpg
-   :scale: 100
-   :alt: Trailer PyPy sprint in Mallorca
-   :align: left
-
-This trailer shows the PyPy team at the sprint in Mallorca, a behind-the-scenes of a typical PyPy coding sprint and talk as well as everything else.
-
-PAL, 11 min, DivX AVI
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/swsnRfj_cek?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Coding discussion of core developers Armin Rigo and Samuele Pedroni
 -------------------------------------------------------------------
 
-620mb: http://buildbot.pypy.org/misc/torrent/coding-discussion-v1.avi.torrent
+Coding discussion between Armin Rigo and Samuele Pedroni during the PyPy
+sprint at the University of Palma de Mallorca, Spain. 27.1.2006
 
-240mb: http://buildbot.pypy.org/misc/torrent/coding-discussion-320x240.avi.torrent
+.. raw:: html
 
-.. image:: image/coding-discussion.jpg
-   :scale: 100
-   :alt: Coding discussion
-   :align: left
-
-Coding discussion between Armin Rigo and Samuele Pedroni during the PyPy sprint at the University of Palma de Mallorca, Spain. 27.1.2006
-
-PAL 40 min, DivX AVI
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/H_IgK9qmEss?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 PyPy technical talk at the University of Palma de Mallorca
 ----------------------------------------------------------
 
-865mb: http://buildbot.pypy.org/misc/torrent/introductory-student-talk-v2.avi.torrent
-
-437mb: http://buildbot.pypy.org/misc/torrent/introductory-student-talk-320x240.avi.torrent
-
-.. image:: image/introductory-student-talk.jpg
-   :scale: 100
-   :alt: Introductory student talk
-   :align: left
-
 Technical talk on the PyPy project at the University of Palma de Mallorca, Spain. 27.1.2006
 
-PAL 72 min, DivX AVI
+Core developers Armin Rigo, Samuele Pedroni and Carl Friedrich Bolz are giving
+an overview of the PyPy architecture, the standard interpreter, the RPython
+translation toolchain and the just-in-time compiler.
 
-Core developers Armin Rigo, Samuele Pedroni and Carl Friedrich Bolz are giving an overview of the PyPy architecture, the standard interpreter, the RPython translation toolchain and the just-in-time compiler.
+.. raw:: html
 
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/6dnUzVQaSlg?rel=0"
+   frameborder="0" allowfullscreen></iframe>
+
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -8,7 +8,11 @@
 .. 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/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/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -496,7 +496,12 @@
 
     # apply kw_spec
     for name, spec in kw_spec.items():
-        unwrap_spec[argnames.index(name)] = spec
+        try:
+            unwrap_spec[argnames.index(name)] = spec
+        except ValueError:
+            raise ValueError("unwrap_spec() got a keyword %r but it is not "
+                             "the name of an argument of the following "
+                             "function" % (name,))
 
     return unwrap_spec
 
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/_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
--- a/pypy/module/_ssl/thread_lock.py
+++ b/pypy/module/_ssl/thread_lock.py
@@ -65,6 +65,8 @@
 
 eci = ExternalCompilationInfo(
     separate_module_sources=[separate_module_source],
+    post_include_bits=[
+        "int _PyPy_SSL_SetupThreads(void);"],
     export_symbols=['_PyPy_SSL_SetupThreads'],
 )
 
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
@@ -9,7 +9,7 @@
 from pypy.objspace.std.multimethod import FailedToImplement
 from pypy.objspace.std.stdtypedef import SMM, StdTypeDef
 from pypy.objspace.std.register_all import register_all
-from pypy.rlib.rarithmetic import ovfcheck
+from pypy.rlib.rarithmetic import ovfcheck, widen
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.objectmodel import specialize, keepalive_until_here
 from pypy.rpython.lltypesystem import lltype, rffi
@@ -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']
@@ -225,20 +227,29 @@
             # length
             self.setlen(0)
 
-        def setlen(self, size):
+        def setlen(self, size, zero=False, overallocate=True):
             if size > 0:
                 if size > self.allocated or size < self.allocated / 2:
-                    if size < 9:
-                        some = 3
+                    if overallocate:
+                        if size < 9:
+                            some = 3
+                        else:
+                            some = 6
+                        some += size >> 3
                     else:
-                        some = 6
-                    some += size >> 3
+                        some = 0
                     self.allocated = size + some
-                    new_buffer = lltype.malloc(mytype.arraytype,
-                                               self.allocated, flavor='raw',
-                                               add_memory_pressure=True)
-                    for i in range(min(size, self.len)):
-                        new_buffer[i] = self.buffer[i]
+                    if zero:
+                        new_buffer = lltype.malloc(mytype.arraytype,
+                                                   self.allocated, flavor='raw',
+                                                   add_memory_pressure=True,
+                                                   zero=True)
+                    else:
+                        new_buffer = lltype.malloc(mytype.arraytype,
+                                                   self.allocated, flavor='raw',
+                                                   add_memory_pressure=True)
+                        for i in range(min(size, self.len)):
+                            new_buffer[i] = self.buffer[i]
                 else:
                     self.len = size
                     return
@@ -344,7 +355,7 @@
     def getitem__Array_Slice(space, self, w_slice):
         start, stop, step, size = space.decode_index4(w_slice, self.len)
         w_a = mytype.w_class(self.space)
-        w_a.setlen(size)
+        w_a.setlen(size, overallocate=False)
         assert step != 0
         j = 0
         for i in range(start, stop, step):
@@ -366,26 +377,18 @@
     def setitem__Array_Slice_Array(space, self, w_idx, w_item):
         start, stop, step, size = self.space.decode_index4(w_idx, self.len)
         assert step != 0
-        if w_item.len != size:
+        if w_item.len != size or self is w_item:
+            # XXX this is a giant slow hack
             w_lst = array_tolist__Array(space, self)
             w_item = space.call_method(w_item, 'tolist')
             space.setitem(w_lst, w_idx, w_item)
             self.setlen(0)
             self.fromsequence(w_lst)
         else:
-            if self is w_item:
-                with lltype.scoped_alloc(mytype.arraytype, self.allocated) as new_buffer:
-                    for i in range(self.len):
-                        new_buffer[i] = w_item.buffer[i]
-                    j = 0
-                    for i in range(start, stop, step):
-                        self.buffer[i] = new_buffer[j]
-                        j += 1
-            else:
-                j = 0
-                for i in range(start, stop, step):
-                    self.buffer[i] = w_item.buffer[j]
-                    j += 1
+            j = 0
+            for i in range(start, stop, step):
+                self.buffer[i] = w_item.buffer[j]
+                j += 1
 
     def setslice__Array_ANY_ANY_ANY(space, self, w_i, w_j, w_x):
         space.setitem(self, space.newslice(w_i, w_j, space.w_None), w_x)
@@ -457,6 +460,7 @@
         self.buffer[i] = val
 
     def delitem__Array_ANY(space, self, w_idx):
+        # XXX this is a giant slow hack
         w_lst = array_tolist__Array(space, self)
         space.delitem(w_lst, w_idx)
         self.setlen(0)
@@ -469,7 +473,7 @@
 
     def add__Array_Array(space, self, other):
         a = mytype.w_class(space)
-        a.setlen(self.len + other.len)
+        a.setlen(self.len + other.len, overallocate=False)
         for i in range(self.len):
             a.buffer[i] = self.buffer[i]
         for i in range(other.len):
@@ -485,46 +489,58 @@
         return self
 
     def mul__Array_ANY(space, self, w_repeat):
+        return _mul_helper(space, self, w_repeat, False)
+
+    def mul__ANY_Array(space, w_repeat, self):
+        return _mul_helper(space, self, w_repeat, False)
+
+    def inplace_mul__Array_ANY(space, self, w_repeat):
+        return _mul_helper(space, self, w_repeat, True)
+
+    def _mul_helper(space, self, w_repeat, is_inplace):
         try:
             repeat = space.getindex_w(w_repeat, space.w_OverflowError)
         except OperationError, e:
             if e.match(space, space.w_TypeError):
                 raise FailedToImplement
             raise
-        a = mytype.w_class(space)
         repeat = max(repeat, 0)
         try:
             newlen = ovfcheck(self.len * repeat)
         except OverflowError:
             raise MemoryError
-        a.setlen(newlen)
-        for r in range(repeat):
-            for i in range(self.len):
-                a.buffer[r * self.len + i] = self.buffer[i]
+        oldlen = self.len
+        if is_inplace:
+            a = self
+            start = 1
+        else:
+            a = mytype.w_class(space)
+            start = 0
+        # <a performance hack>
+        if oldlen == 1:
+            if mytype.unwrap == 'str_w' or mytype.unwrap == 'unicode_w':
+                zero = not ord(self.buffer[0])
+            elif mytype.unwrap == 'int_w' or mytype.unwrap == 'bigint_w':
+                zero = not widen(self.buffer[0])
+            #elif mytype.unwrap == 'float_w':
+            #    value = ...float(self.buffer[0])  xxx handle the case of -0.0
+            else:
+                zero = False
+            if zero:
+                a.setlen(newlen, zero=True, overallocate=False)
+                return a
+            a.setlen(newlen, overallocate=False)
+            item = self.buffer[0]
+            for r in range(start, repeat):
+                a.buffer[r] = item
+            return a
+        # </a performance hack>
+        a.setlen(newlen, overallocate=False)
+        for r in range(start, repeat):
+            for i in range(oldlen):
+                a.buffer[r * oldlen + i] = self.buffer[i]
         return a
 
-    def mul__ANY_Array(space, w_repeat, self):
-        return mul__Array_ANY(space, self, w_repeat)
-
-    def inplace_mul__Array_ANY(space, self, w_repeat):
-        try:
-            repeat = space.getindex_w(w_repeat, space.w_OverflowError)
-        except OperationError, e:
-            if e.match(space, space.w_TypeError):
-                raise FailedToImplement
-            raise
-        oldlen = self.len
-        repeat = max(repeat, 0)
-        try:
-            newlen = ovfcheck(self.len * repeat)
-        except OverflowError:
-            raise MemoryError
-        self.setlen(newlen)
-        for r in range(1, repeat):
-            for i in range(oldlen):
-                self.buffer[r * oldlen + i] = self.buffer[i]
-        return self
-
     # Convertions
 
     def array_tolist__Array(space, self):
@@ -600,6 +616,7 @@
     # Compare methods
     @specialize.arg(3)
     def _cmp_impl(space, self, other, space_fn):
+        # XXX this is a giant slow hack
         w_lst1 = array_tolist__Array(space, self)
         w_lst2 = space.call_method(other, 'tolist')
         return space_fn(w_lst1, w_lst2)
@@ -646,7 +663,7 @@
 
     def array_copy__Array(space, self):
         w_a = mytype.w_class(self.space)
-        w_a.setlen(self.len)
+        w_a.setlen(self.len, overallocate=False)
         rffi.c_memcpy(
             rffi.cast(rffi.VOIDP, w_a.buffer),
             rffi.cast(rffi.VOIDP, self.buffer),
diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -890,6 +890,54 @@
         a[::-1] = a
         assert a == self.array('b', [3, 2, 1, 0])
 
+    def test_array_multiply(self):
+        a = self.array('b', [0])
+        b = a * 13
+        assert b[12] == 0
+        b = 13 * a
+        assert b[12] == 0
+        a *= 13
+        assert a[12] == 0
+        a = self.array('b', [1])
+        b = a * 13
+        assert b[12] == 1
+        b = 13 * a
+        assert b[12] == 1
+        a *= 13
+        assert a[12] == 1
+        a = self.array('i', [0])
+        b = a * 13
+        assert b[12] == 0
+        b = 13 * a
+        assert b[12] == 0
+        a *= 13
+        assert a[12] == 0
+        a = self.array('i', [1])
+        b = a * 13
+        assert b[12] == 1
+        b = 13 * a
+        assert b[12] == 1
+        a *= 13
+        assert a[12] == 1
+        a = self.array('i', [0, 0])
+        b = a * 13
+        assert len(b) == 26
+        assert b[22] == 0
+        b = 13 * a
+        assert len(b) == 26
+        assert b[22] == 0
+        a *= 13
+        assert a[22] == 0
+        assert len(a) == 26
+        a = self.array('f', [-0.0])
+        b = a * 13
+        assert len(b) == 13
+        assert str(b[12]) == "-0.0"
+        a = self.array('d', [-0.0])
+        b = a * 13
+        assert len(b) == 13
+        assert str(b[12]) == "-0.0"
+
 
 class AppTestArrayBuiltinShortcut(AppTestArray):
     OPTIONS = {'objspace.std.builtinshortcut': True}
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) {
+   case 0:
+      return arg0;
+   case 1:
+      return arg1;
+   default:
+      break;
+   }
+
+   return "argn invalid";
+}
+
+std::string ArgPasser::stringRef(const std::string& arg0, int argn, const std::string& arg1)
+{
+   return stringValue(arg0, argn, arg1);
+}
+
+
+// special case naming
+z_& z_::gime_z_(z_& z) { return z; }
diff --git a/pypy/module/cppyy/test/example01.h b/pypy/module/cppyy/test/example01.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/example01.h
@@ -0,0 +1,111 @@
+#include <string>
+
+class payload {
+public:
+    payload(double d = 0.);
+    payload(const payload& p);
+    payload& operator=(const payload& e);
+    ~payload();
+
+    double getData();
+    void setData(double d);
+
+public:        // class-level data
+    static int count;
+
+private:
+    double m_data;
+};
+
+
+class example01 {
+public:
+    example01();
+    example01(int a);
+    example01(const example01& e);
+    example01& operator=(const example01& e);
+    virtual ~example01();
+
+public:        // class-level methods
+    static int staticAddOneToInt(int a);
+    static int staticAddOneToInt(int a, int b);
+    static double staticAddToDouble(double a);
+    static int staticAtoi(const char* str);
+    static char* staticStrcpy(const char* strin);
+    static void staticSetPayload(payload* p, double d);
+    static payload* staticCyclePayload(payload* p, double d);
+    static payload staticCopyCyclePayload(payload* p, double d);
+    static int getCount();
+    static void setCount(int);
+
+public:        // instance methods
+    int addDataToInt(int a);
+    int addDataToIntConstRef(const int& a);
+    int overloadedAddDataToInt(int a, int b);
+    int overloadedAddDataToInt(int a);
+    int overloadedAddDataToInt(int a, int b, int c);
+    double addDataToDouble(double a);
+    int addDataToAtoi(const char* str);
+    char* addToStringValue(const char* str);
+
+    void setPayload(payload* p);
+    payload* cyclePayload(payload* p);
+    payload copyCyclePayload(payload* p);
+
+public:        // class-level data
+    static int count;
+
+public:        // instance data
+    int m_somedata;
+};
+
+
+// global functions
+int globalAddOneToInt(int a);
+namespace ns_example01 {
+    int globalAddOneToInt(int a);
+}
+
+#define itypeValue(itype, tname) \
+   itype tname##Value(itype arg0, int argn=0, itype arg1=1, itype arg2=2)
+
+#define ftypeValue(ftype) \
+   ftype ftype##Value(ftype arg0, int argn=0, ftype arg1=1., ftype arg2=2.)
+
+// argument passing
+class ArgPasser {        // use a class for now as methptrgetter not
+public:                  // implemented for global functions
+   itypeValue(short, short);
+   itypeValue(unsigned short, ushort);
+   itypeValue(int, int);
+   itypeValue(unsigned int, uint);
+   itypeValue(long, long);
+   itypeValue(unsigned long, ulong);
+
+   ftypeValue(float);
+   ftypeValue(double);
+
+   std::string stringValue(
+      std::string arg0, int argn=0, std::string arg1 = "default");
+
+   std::string stringRef(
+      const std::string& arg0, int argn=0, const std::string& arg1="default");
+};
+
+
+// typedefs
+typedef example01 example01_t;
+
+
+// special case naming
+class z_ {
+public:
+   z_& gime_z_(z_& z);
+   int myint;
+};
+
+// for pythonization checking
+class example01a : public example01 {
+public:
+   example01a(int a) : example01(a) {}
+};
diff --git a/pypy/module/cppyy/test/example01.xml b/pypy/module/cppyy/test/example01.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/example01.xml
@@ -0,0 +1,17 @@
+<lcgdict>
+
+  <class name="payload" />
+  <class name="example01" />
+  <class name="example01_t" />
+  <class name="example01a" />
+  <class name="std::string" />
+  <class name="z_" />
+
+  <function name="globalAddOneToInt" />
+
+  <namespace name="ns_example01" />
+  <function name="ns_example01::globalAddOneToInt" />
+
+  <class name="ArgPasser" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/example01_LinkDef.h b/pypy/module/cppyy/test/example01_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/example01_LinkDef.h
@@ -0,0 +1,19 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class example01;
+#pragma link C++ typedef example01_t;
+#pragma link C++ class example01a;
+#pragma link C++ class payload;
+#pragma link C++ class ArgPasser;
+#pragma link C++ class z_;
+
+#pragma link C++ function globalAddOneToInt(int);
+
+#pragma link C++ namespace ns_example01;
+#pragma link C++ function ns_example01::globalAddOneToInt(int);
+
+#endif
diff --git a/pypy/module/cppyy/test/fragile.cxx b/pypy/module/cppyy/test/fragile.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/fragile.cxx
@@ -0,0 +1,11 @@
+#include "fragile.h"
+
+fragile::H::HH* fragile::H::HH::copy() {
+    return (HH*)0;
+}
+
+fragile::I fragile::gI;
+
+void fragile::fglobal(int, double, char) {
+    /* empty; only used for doc-string testing */
+}
diff --git a/pypy/module/cppyy/test/fragile.h b/pypy/module/cppyy/test/fragile.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/fragile.h
@@ -0,0 +1,80 @@
+namespace fragile {
+
+class no_such_class;
+
+class A {
+public:
+    virtual int check() { return (int)'A'; }
+    virtual A* gime_null() { return (A*)0; }
+};
+
+class B {
+public:
+    virtual int check() { return (int)'B'; }
+    no_such_class* gime_no_such() { return 0; }
+};
+
+class C {
+public:
+    virtual int check() { return (int)'C'; }
+    void use_no_such(no_such_class*) {}
+};
+
+class D {
+public:
+    virtual int check() { return (int)'D'; }
+    void overload() {}
+    void overload(no_such_class*) {}
+    void overload(char, int i = 0) {}  // Reflex requires a named arg
+    void overload(int, no_such_class* p = 0) {}
+};
+
+class E {
+public:
+    E() : m_pp_no_such(0), m_pp_a(0) {}
+
+    virtual int check() { return (int)'E'; }
+    void overload(no_such_class**) {}
+
+    no_such_class** m_pp_no_such;
+    A** m_pp_a;
+};
+
+class F {
+public:
+    F() : m_int(0) {}
+    virtual int check() { return (int)'F'; }
+    int m_int;
+};
+
+class G {
+public:
+    enum { unnamed1=24, unnamed2=96 };
+
+    class GG {};
+};
+
+class H {
+public:
+    class HH {
+    public:
+       HH* copy();
+    };
+    HH* m_h;
+};
+
+class I {
+public:
+    operator bool() { return 0; }
+};
+
+extern I gI;
+
+class J {
+public:
+    int method1(int, double) { return 0; }
+};
+
+void fglobal(int, double, char);
+
+} // namespace fragile
diff --git a/pypy/module/cppyy/test/fragile.xml b/pypy/module/cppyy/test/fragile.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/fragile.xml
@@ -0,0 +1,11 @@
+<lcgdict>
+
+  <namespace name="fragile" />
+
+  <class pattern="fragile::[A-Z]" />
+
+  <variable name="fragile::gI" />
+
+  <function pattern="fragile::f*" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/fragile_LinkDef.h b/pypy/module/cppyy/test/fragile_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/fragile_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++ namespace fragile;
+
+#pragma link C++ class fragile::A;
+#pragma link C++ class fragile::B;
+#pragma link C++ class fragile::C;
+#pragma link C++ class fragile::D;
+#pragma link C++ class fragile::E;
+#pragma link C++ class fragile::F;
+#pragma link C++ class fragile::G;
+#pragma link C++ class fragile::H;
+#pragma link C++ class fragile::I;
+#pragma link C++ class fragile::J;
+
+#pragma link C++ variable fragile::gI;
+
+#pragma link C++ function fragile::fglobal;
+
+#endif
diff --git a/pypy/module/cppyy/test/operators.cxx b/pypy/module/cppyy/test/operators.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/operators.cxx
@@ -0,0 +1,1 @@
+#include "operators.h"
diff --git a/pypy/module/cppyy/test/operators.h b/pypy/module/cppyy/test/operators.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/operators.h
@@ -0,0 +1,95 @@
+class number  {
+public:
+   number() { m_int = 0; }
+   number(int i) { m_int = i; }
+
+   number operator+(const number& n) const { return number(m_int + n.m_int); }
+   number operator+(int n) const { return number(m_int + n); }
+   number operator-(const number& n) const { return number(m_int - n.m_int); }
+   number operator-(int n) const { return number(m_int - n); }
+   number operator*(const number& n) const { return number(m_int * n.m_int); }
+   number operator*(int n) const { return number(m_int * n); }
+   number operator/(const number& n) const { return number(m_int / n.m_int); }
+   number operator/(int n) const { return number(m_int / n); }
+   number operator%(const number& n) const { return number(m_int % n.m_int); }
+   number operator%(int n) const { return number(m_int % n); }
+
+   number& operator+=(const number& n) { m_int += n.m_int; return *this; }
+   number& operator-=(const number& n) { m_int -= n.m_int; return *this; }
+   number& operator*=(const number& n) { m_int *= n.m_int; return *this; }
+   number& operator/=(const number& n) { m_int /= n.m_int; return *this; }
+   number& operator%=(const number& n) { m_int %= n.m_int; return *this; }
+
+   number operator-() { return number( -m_int ); }
+
+   bool operator<(const number& n) const { return m_int < n.m_int; }
+   bool operator>(const number& n) const { return m_int > n.m_int; }
+   bool operator<=(const number& n) const { return m_int <= n.m_int; }
+   bool operator>=(const number& n) const { return m_int >= n.m_int; }
+   bool operator!=(const number& n) const { return m_int != n.m_int; }
+   bool operator==(const number& n) const { return m_int == n.m_int; }
+
+   operator bool() { return m_int != 0; }
+
+   number operator&(const number& n) const { return number(m_int & n.m_int); }
+   number operator|(const number& n) const { return number(m_int | n.m_int); }
+   number operator^(const number& n) const { return number(m_int ^ n.m_int); }
+
+   number& operator&=(const number& n) { m_int &= n.m_int; return *this; }
+   number& operator|=(const number& n) { m_int |= n.m_int; return *this; }
+   number& operator^=(const number& n) { m_int ^= n.m_int; return *this; }
+
+   number operator<<(int i) const { return number(m_int << i); }
+   number operator>>(int i) const { return number(m_int >> i); }
+
+private:
+   int m_int;
+};
+
+//----------------------------------------------------------------------------
+struct operator_char_star {       // for testing user-defined implicit casts
+   operator_char_star() : m_str((char*)"operator_char_star") {}
+   operator char*() { return m_str; }
+   char* m_str;
+};
+
+struct operator_const_char_star {
+   operator_const_char_star() : m_str("operator_const_char_star" ) {}
+   operator const char*() { return m_str; }
+   const char* m_str;
+};
+
+struct operator_int {
+   operator int() { return m_int; }
+   int m_int;
+};
+
+struct operator_long {
+   operator long() { return m_long; }
+   long m_long;
+};
+
+struct operator_double {
+   operator double() { return m_double; }
+   double m_double;
+};
+
+struct operator_short {
+   operator short() { return m_short; }
+   unsigned short m_short;
+};
+
+struct operator_unsigned_int {
+   operator unsigned int() { return m_uint; }
+   unsigned int m_uint;
+};
+
+struct operator_unsigned_long {
+   operator unsigned long() { return m_ulong; }
+   unsigned long m_ulong;
+};
+
+struct operator_float {
+   operator float() { return m_float; }
+   float m_float;
+};
diff --git a/pypy/module/cppyy/test/operators.xml b/pypy/module/cppyy/test/operators.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/operators.xml
@@ -0,0 +1,6 @@
+<lcgdict>
+
+  <class name="number" />
+  <class pattern="operator_*" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/operators_LinkDef.h b/pypy/module/cppyy/test/operators_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/operators_LinkDef.h
@@ -0,0 +1,19 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class number;
+
+#pragma link C++ struct operator_char_star;
+#pragma link C++ struct operator_const_char_star;
+#pragma link C++ struct operator_int;
+#pragma link C++ struct operator_long;
+#pragma link C++ struct operator_double;
+#pragma link C++ struct operator_short;
+#pragma link C++ struct operator_unsigned_int;
+#pragma link C++ struct operator_unsigned_long;
+#pragma link C++ struct operator_float;
+
+#endif
diff --git a/pypy/module/cppyy/test/overloads.cxx b/pypy/module/cppyy/test/overloads.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/overloads.cxx
@@ -0,0 +1,49 @@
+#include "overloads.h"
+
+
+a_overload::a_overload() { i1 = 42; i2 = -1; }
+
+ns_a_overload::a_overload::a_overload() { i1 = 88; i2 = -34; }
+int ns_a_overload::b_overload::f(const std::vector<int>* v) { return (*v)[0]; }
+
+ns_b_overload::a_overload::a_overload() { i1 = -33; i2 = 89; }
+
+b_overload::b_overload() { i1 = -2; i2 = 13; }
+
+c_overload::c_overload() {}
+int c_overload::get_int(a_overload* a)                { return a->i1; }
+int c_overload::get_int(ns_a_overload::a_overload* a) { return a->i1; }
+int c_overload::get_int(ns_b_overload::a_overload* a) { return a->i1; }
+int c_overload::get_int(short* p)                     { return *p; }
+int c_overload::get_int(b_overload* b)                { return b->i2; }
+int c_overload::get_int(int* p)                       { return *p; }
+
+d_overload::d_overload() {}
+int d_overload::get_int(int* p)                       { return *p; }
+int d_overload::get_int(b_overload* b)                { return b->i2; }
+int d_overload::get_int(short* p)                     { return *p; }
+int d_overload::get_int(ns_b_overload::a_overload* a) { return a->i1; }
+int d_overload::get_int(ns_a_overload::a_overload* a) { return a->i1; }
+int d_overload::get_int(a_overload* a)                { return a->i1; }
+
+
+more_overloads::more_overloads() {}
+std::string more_overloads::call(const aa_ol&) { return "aa_ol"; }
+std::string more_overloads::call(const bb_ol&, void* n) { n = 0; return "bb_ol"; }
+std::string more_overloads::call(const cc_ol&) { return "cc_ol"; }
+std::string more_overloads::call(const dd_ol&) { return "dd_ol"; }
+
+std::string more_overloads::call_unknown(const dd_ol&) { return "dd_ol"; }
+
+std::string more_overloads::call(double)  { return "double"; }
+std::string more_overloads::call(int)     { return "int"; }
+std::string more_overloads::call1(int)    { return "int"; }
+std::string more_overloads::call1(double) { return "double"; }
+
+
+more_overloads2::more_overloads2() {}
+std::string more_overloads2::call(const bb_ol&) { return "bb_olref"; }
+std::string more_overloads2::call(const bb_ol*) { return "bb_olptr"; }
+
+std::string more_overloads2::call(const dd_ol*, int) { return "dd_olptr"; }
+std::string more_overloads2::call(const dd_ol&, int) { return "dd_olref"; }
diff --git a/pypy/module/cppyy/test/overloads.h b/pypy/module/cppyy/test/overloads.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/overloads.h
@@ -0,0 +1,90 @@
+#include <string>
+#include <vector>
+
+class a_overload {
+public:
+   a_overload();
+   int i1, i2;
+};
+
+namespace ns_a_overload {
+   class a_overload {
+   public:
+      a_overload();
+      int i1, i2;
+   };
+
+   class b_overload {
+   public:
+      int f(const std::vector<int>* v);
+   };
+}
+
+namespace ns_b_overload {
+   class a_overload {
+   public:
+      a_overload();
+      int i1, i2;
+   };
+}
+
+class b_overload {
+public:
+   b_overload();
+   int i1, i2;
+};
+
+class c_overload {
+public:
+   c_overload();
+   int get_int(a_overload* a);
+   int get_int(ns_a_overload::a_overload* a);
+   int get_int(ns_b_overload::a_overload* a);
+   int get_int(short* p);
+   int get_int(b_overload* b);
+   int get_int(int* p);
+};
+
+class d_overload {
+public:
+   d_overload();
+//   int get_int(void* p) { return *(int*)p; }
+   int get_int(int* p);
+   int get_int(b_overload* b);
+   int get_int(short* p);
+   int get_int(ns_b_overload::a_overload* a);
+   int get_int(ns_a_overload::a_overload* a);
+   int get_int(a_overload* a);
+};
+
+
+class aa_ol {};
+class bb_ol;
+class cc_ol {};
+class dd_ol;
+
+class more_overloads {
+public:
+   more_overloads();
+   std::string call(const aa_ol&);
+   std::string call(const bb_ol&, void* n=0);
+   std::string call(const cc_ol&);
+   std::string call(const dd_ol&);
+
+   std::string call_unknown(const dd_ol&);
+
+   std::string call(double);
+   std::string call(int);
+   std::string call1(int);
+   std::string call1(double);
+};
+
+class more_overloads2 {
+public:
+   more_overloads2();
+   std::string call(const bb_ol&);
+   std::string call(const bb_ol*);
+
+   std::string call(const dd_ol*, int);
+   std::string call(const dd_ol&, int);
+};
diff --git a/pypy/module/cppyy/test/overloads.xml b/pypy/module/cppyy/test/overloads.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/overloads.xml
@@ -0,0 +1,14 @@
+<lcgdict>
+
+  <class name="std::string" />
+
+  <class pattern="*_overload" />
+
+  <namespace pattern="ns_*_overload" />
+  <class pattern="ns_*_overload::*_overload" />
+
+  <class pattern="*_ol" />
+  <class name="more_overloads" />
+  <class name="more_overloads2" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/overloads_LinkDef.h b/pypy/module/cppyy/test/overloads_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/overloads_LinkDef.h
@@ -0,0 +1,25 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class a_overload;
+#pragma link C++ class b_overload;
+#pragma link C++ class c_overload;
+#pragma link C++ class d_overload;
+
+#pragma link C++ namespace ns_a_overload;
+#pragma link C++ class ns_a_overload::a_overload;
+#pragma link C++ class ns_a_overload::b_overload;
+
+#pragma link C++ class ns_b_overload;
+#pragma link C++ class ns_b_overload::a_overload;
+
+#pragma link C++ class aa_ol;
+#pragma link C++ class cc_ol;
+
+#pragma link C++ class more_overloads;
+#pragma link C++ class more_overloads2;
+
+#endif
diff --git a/pypy/module/cppyy/test/std_streams.cxx b/pypy/module/cppyy/test/std_streams.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/std_streams.cxx
@@ -0,0 +1,3 @@
+#include "std_streams.h"
+
+template class std::basic_ios<char,std::char_traits<char> >;
diff --git a/pypy/module/cppyy/test/std_streams.h b/pypy/module/cppyy/test/std_streams.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/std_streams.h
@@ -0,0 +1,13 @@
+#ifndef STD_STREAMS_H 
+#define STD_STREAMS_H 1
+
+#ifndef __CINT__
+#include <ios>
+#endif
+#include <iostream>
+
+#ifndef __CINT__
+extern template class std::basic_ios<char,std::char_traits<char> >;
+#endif
+
+#endif // STD_STREAMS_H
diff --git a/pypy/module/cppyy/test/std_streams.xml b/pypy/module/cppyy/test/std_streams.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/std_streams.xml
@@ -0,0 +1,7 @@
+<lcgdict>
+
+  <class name = "std::ostream"/>
+  <class name = "std::ios_base"/>
+  <class name = "std::basic_ios<char,std::char_traits<char> >"/>
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/std_streams_LinkDef.h b/pypy/module/cppyy/test/std_streams_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/std_streams_LinkDef.h
@@ -0,0 +1,9 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class std::ostream;
+
+#endif
diff --git a/pypy/module/cppyy/test/stltypes.cxx b/pypy/module/cppyy/test/stltypes.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/stltypes.cxx
@@ -0,0 +1,26 @@
+#include "stltypes.h"
+
+#define STLTYPES_EXPLICIT_INSTANTIATION(STLTYPE, TTYPE)                         \
+template class std::STLTYPE< TTYPE >;                                           \
+template class __gnu_cxx::__normal_iterator<TTYPE*, std::STLTYPE< TTYPE > >;    \
+template class __gnu_cxx::__normal_iterator<const TTYPE*, std::STLTYPE< TTYPE > >;\
+namespace __gnu_cxx {                                                           \
+template bool operator==(const std::STLTYPE< TTYPE >::iterator&,                \
+                         const std::STLTYPE< TTYPE >::iterator&);               \
+template bool operator!=(const std::STLTYPE< TTYPE >::iterator&,                \
+                         const std::STLTYPE< TTYPE >::iterator&);               \
+}
+
+
+//- explicit instantiations of used types
+STLTYPES_EXPLICIT_INSTANTIATION(vector, int)
+STLTYPES_EXPLICIT_INSTANTIATION(vector, just_a_class)
+
+//- class with lots of std::string handling
+stringy_class::stringy_class(const char* s) : m_string(s) {}
+
+std::string stringy_class::get_string1() { return m_string; }
+void stringy_class::get_string2(std::string& s) { s = m_string; }
+
+void stringy_class::set_string1(const std::string& s) { m_string = s; }
+void stringy_class::set_string2(std::string s) { m_string = s; }
diff --git a/pypy/module/cppyy/test/stltypes.h b/pypy/module/cppyy/test/stltypes.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/stltypes.h
@@ -0,0 +1,44 @@
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+#define STLTYPES_EXPLICIT_INSTANTIATION_DECL(STLTYPE, TTYPE)                    \
+extern template class std::STLTYPE< TTYPE >;                                    \
+extern template class __gnu_cxx::__normal_iterator<TTYPE*, std::STLTYPE< TTYPE > >;\
+extern template class __gnu_cxx::__normal_iterator<const TTYPE*, std::STLTYPE< TTYPE > >;\
+namespace __gnu_cxx {                                                           \
+extern template bool operator==(const std::STLTYPE< TTYPE >::iterator&,         \
+                         const std::STLTYPE< TTYPE >::iterator&);               \
+extern template bool operator!=(const std::STLTYPE< TTYPE >::iterator&,         \
+                         const std::STLTYPE< TTYPE >::iterator&);               \
+}
+
+
+//- basic example class
+class just_a_class {
+public:
+    int m_i;
+};
+
+
+#ifndef __CINT__
+//- explicit instantiations of used types
+STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, int)
+STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, just_a_class)
+#endif
+
+
+//- class with lots of std::string handling
+class stringy_class {
+public:
+   stringy_class(const char* s);
+
+   std::string get_string1();
+   void get_string2(std::string& s);
+
+   void set_string1(const std::string& s);
+   void set_string2(std::string s);
+
+   std::string m_string;
+};
diff --git a/pypy/module/cppyy/test/stltypes.xml b/pypy/module/cppyy/test/stltypes.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/stltypes.xml
@@ -0,0 +1,20 @@
+<lcgdict>
+
+  <namespace name="std" />
+
+  <class pattern="std::vector<*>" />
+  <class pattern="__gnu_cxx::__normal_iterator<*>" />
+  <class pattern="__gnu_cxx::new_allocator<*>" />
+  <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!="/>
+
+  <class name="just_a_class" />
+
+  <class name="std::string" />
+  <class name="stringy_class" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/stltypes_LinkDef.h b/pypy/module/cppyy/test/stltypes_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/stltypes_LinkDef.h
@@ -0,0 +1,14 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class std::vector<just_a_class>;
+#pragma link C++ class std::vector<just_a_class>::iterator;
+#pragma link C++ class std::vector<just_a_class>::const_iterator;
+
+#pragma link C++ class just_a_class;
+#pragma link C++ class stringy_class;
+
+#endif
diff --git a/pypy/module/cppyy/test/test_aclassloader.py b/pypy/module/cppyy/test/test_aclassloader.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_aclassloader.py
@@ -0,0 +1,26 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+
+
+currpath = py.path.local(__file__).dirpath()
+
+def setup_module(mod):
+    if sys.platform == 'win32':
+        py.test.skip("win32 not supported so far")
+    err = os.system("cd '%s' && make example01Dict.so" % currpath)
+    if err:
+        raise OSError("'make' failed (see stderr)")
+
+
+class AppTestACLASSLOADER:
+    def setup_class(cls):
+        cls.space = gettestobjspace(usemodules=['cppyy'])
+
+    def test01_class_autoloading(self):
+        """Test whether a class can be found through .rootmap."""
+        import cppyy
+        example01_class = cppyy.gbl.example01
+        assert example01_class
+        cl2 = cppyy.gbl.example01
+        assert cl2
+        assert example01_class is cl2
diff --git a/pypy/module/cppyy/test/test_advancedcpp.py b/pypy/module/cppyy/test/test_advancedcpp.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_advancedcpp.py
@@ -0,0 +1,489 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+
+from pypy.module.cppyy import capi
+
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("advancedcppDict.so"))
+
+space = gettestobjspace(usemodules=['cppyy'])
+
+def setup_module(mod):
+    if sys.platform == 'win32':
+        py.test.skip("win32 not supported so far")
+    for refl_dict in ["advancedcppDict.so", "advancedcpp2Dict.so"]:
+        err = os.system("cd '%s' && make %s" % (currpath, refl_dict))
+        if err:
+            raise OSError("'make' failed (see stderr)")
+
+class AppTestADVANCEDCPP:
+    def setup_class(cls):
+        cls.space = space
+        env = os.environ
+        cls.w_test_dct = space.wrap(test_dct)
+        cls.w_capi_identity = space.wrap(capi.identify())
+        cls.w_advanced = cls.space.appexec([], """():
+            import cppyy
+            return cppyy.load_reflection_info(%r)""" % (test_dct, ))
+
+    def test01_default_arguments(self):
+        """Test usage of default arguments"""
+
+        import cppyy
+        defaulter = cppyy.gbl.defaulter
+
+        d = defaulter()
+        assert d.m_a == 11
+        assert d.m_b == 22
+        assert d.m_c == 33
+        d.destruct()
+
+        d = defaulter(0)
+        assert d.m_a ==  0
+        assert d.m_b == 22
+        assert d.m_c == 33
+        d.destruct()
+
+        d = defaulter(1, 2)
+        assert d.m_a ==  1
+        assert d.m_b ==  2
+        assert d.m_c == 33
+        d.destruct()
+
+        d = defaulter(3, 4, 5)
+        assert d.m_a ==  3
+        assert d.m_b ==  4
+        assert d.m_c ==  5
+        d.destruct()
+
+    def test02_simple_inheritance(self):
+        """Test binding of a basic inheritance structure"""
+
+        import cppyy
+        base_class    = cppyy.gbl.base_class
+        derived_class = cppyy.gbl.derived_class
+
+        assert issubclass(derived_class, base_class)
+        assert not issubclass(base_class, derived_class)
+
+        b = base_class()
+        assert isinstance(b, base_class)
+        assert not isinstance(b, derived_class)
+
+        assert b.m_b              == 1
+        assert b.get_value()      == 1
+        assert b.m_db             == 1.1
+        assert b.get_base_value() == 1.1
+
+        b.m_b, b.m_db = 11, 11.11
+        assert b.m_b              == 11
+        assert b.get_value()      == 11
+        assert b.m_db             == 11.11
+        assert b.get_base_value() == 11.11
+
+        b.destruct()
+
+        d = derived_class()
+        assert isinstance(d, derived_class)
+        assert isinstance(d, base_class)
+
+        assert d.m_d                 == 2
+        assert d.get_value()         == 2
+        assert d.m_dd                == 2.2
+        assert d.get_derived_value() == 2.2
+
+        assert d.m_b                 == 1
+        assert d.m_db                == 1.1
+        assert d.get_base_value()    == 1.1
+
+        d.m_b, d.m_db = 11, 11.11
+        d.m_d, d.m_dd = 22, 22.22
+
+        assert d.m_d                 == 22
+        assert d.get_value()         == 22
+        assert d.m_dd                == 22.22
+        assert d.get_derived_value() == 22.22
+
+        assert d.m_b                 == 11
+        assert d.m_db                == 11.11
+        assert d.get_base_value()    == 11.11
+
+        d.destruct()
+
+    def test03_namespaces(self):
+        """Test access to namespaces and inner classes"""
+
+        import cppyy
+        gbl = cppyy.gbl
+
+        assert gbl.a_ns      is gbl.a_ns
+        assert gbl.a_ns.d_ns is gbl.a_ns.d_ns
+
+        assert gbl.a_ns.b_class              is gbl.a_ns.b_class
+        assert gbl.a_ns.b_class.c_class      is gbl.a_ns.b_class.c_class
+        assert gbl.a_ns.d_ns.e_class         is gbl.a_ns.d_ns.e_class
+        assert gbl.a_ns.d_ns.e_class.f_class is gbl.a_ns.d_ns.e_class.f_class
+
+        assert gbl.a_ns.g_a                           == 11
+        assert gbl.a_ns.get_g_a()                     == 11
+        assert gbl.a_ns.b_class.s_b                   == 22
+        assert gbl.a_ns.b_class().m_b                 == -2
+        assert gbl.a_ns.b_class.c_class.s_c           == 33
+        assert gbl.a_ns.b_class.c_class().m_c         == -3
+        assert gbl.a_ns.d_ns.g_d                      == 44
+        assert gbl.a_ns.d_ns.get_g_d()                == 44
+        assert gbl.a_ns.d_ns.e_class.s_e              == 55
+        assert gbl.a_ns.d_ns.e_class().m_e            == -5
+        assert gbl.a_ns.d_ns.e_class.f_class.s_f      == 66
+        assert gbl.a_ns.d_ns.e_class.f_class().m_f    == -6
+
+    def test03a_namespace_lookup_on_update(self):
+        """Test whether namespaces can be shared across dictionaries."""
+
+        import cppyy
+        gbl = cppyy.gbl
+
+        lib2 = cppyy.load_reflection_info("advancedcpp2Dict.so")
+
+        assert gbl.a_ns      is gbl.a_ns
+        assert gbl.a_ns.d_ns is gbl.a_ns.d_ns
+
+        assert gbl.a_ns.g_class              is gbl.a_ns.g_class
+        assert gbl.a_ns.g_class.h_class      is gbl.a_ns.g_class.h_class
+        assert gbl.a_ns.d_ns.i_class         is gbl.a_ns.d_ns.i_class
+        assert gbl.a_ns.d_ns.i_class.j_class is gbl.a_ns.d_ns.i_class.j_class
+
+        assert gbl.a_ns.g_g                           ==  77
+        assert gbl.a_ns.get_g_g()                     ==  77
+        assert gbl.a_ns.g_class.s_g                   ==  88
+        assert gbl.a_ns.g_class().m_g                 ==  -7
+        assert gbl.a_ns.g_class.h_class.s_h           ==  99
+        assert gbl.a_ns.g_class.h_class().m_h         ==  -8
+        assert gbl.a_ns.d_ns.g_i                      == 111
+        assert gbl.a_ns.d_ns.get_g_i()                == 111
+        assert gbl.a_ns.d_ns.i_class.s_i              == 222
+        assert gbl.a_ns.d_ns.i_class().m_i            ==  -9
+        assert gbl.a_ns.d_ns.i_class.j_class.s_j      == 333
+        assert gbl.a_ns.d_ns.i_class.j_class().m_j    == -10
+
+    def test04_template_types(self):
+        """Test bindings of templated types"""
+
+        import cppyy
+        gbl = cppyy.gbl
+
+        assert gbl.T1 is gbl.T1
+        assert gbl.T2 is gbl.T2
+        assert gbl.T3 is gbl.T3
+        assert not gbl.T1 is gbl.T2
+        assert not gbl.T2 is gbl.T3
+
+        assert gbl.T1('int') is gbl.T1('int')
+        assert gbl.T1(int)   is gbl.T1('int')
+        assert gbl.T2('T1<int>')     is gbl.T2('T1<int>')
+        assert gbl.T2(gbl.T1('int')) is gbl.T2('T1<int>')
+        assert gbl.T2(gbl.T1(int)) is gbl.T2('T1<int>')
+        assert gbl.T3('int,double')    is gbl.T3('int,double')
+        assert gbl.T3('int', 'double') is gbl.T3('int,double')
+        assert gbl.T3(int, 'double')   is gbl.T3('int,double')
+        assert gbl.T3('T1<int>,T2<T1<int> >') is gbl.T3('T1<int>,T2<T1<int> >')
+        assert gbl.T3('T1<int>', gbl.T2(gbl.T1(int))) is gbl.T3('T1<int>,T2<T1<int> >')
+
+        assert gbl.a_ns.T4(int) is gbl.a_ns.T4('int')
+        assert gbl.a_ns.T4('a_ns::T4<T3<int,double> >')\
+               is gbl.a_ns.T4(gbl.a_ns.T4(gbl.T3(int, 'double')))
+
+        #-----
+        t1 = gbl.T1(int)()
+        assert t1.m_t1    == 1
+        assert t1.value() == 1
+        t1.destruct()
+
+        #-----
+        t1 = gbl.T1(int)(11)
+        assert t1.m_t1    == 11
+        assert t1.value() == 11
+        t1.m_t1 = 111
+        assert t1.value() == 111
+        assert t1.m_t1    == 111
+        t1.destruct()
+
+        #-----
+        t2 = gbl.T2(gbl.T1(int))(gbl.T1(int)(32))
+        t2.m_t2.m_t1 = 32
+        assert t2.m_t2.value() == 32
+        assert t2.m_t2.m_t1    == 32
+        t2.destruct()
+
+    def test05_abstract_classes(self):
+        """Test non-instatiatability of abstract classes"""
+
+        import cppyy
+        gbl = cppyy.gbl
+
+        raises(TypeError, gbl.a_class)
+        raises(TypeError, gbl.some_abstract_class)
+
+        assert issubclass(gbl.some_concrete_class, gbl.some_abstract_class)
+
+        c = gbl.some_concrete_class()
+        assert isinstance(c, gbl.some_concrete_class)
+        assert isinstance(c, gbl.some_abstract_class)
+
+    def test06_datamembers(self):
+        """Test data member access when using virtual inheritence"""
+
+        import cppyy
+        a_class   = cppyy.gbl.a_class
+        b_class   = cppyy.gbl.b_class
+        c_class_1 = cppyy.gbl.c_class_1
+        c_class_2 = cppyy.gbl.c_class_2
+        d_class   = cppyy.gbl.d_class
+
+        assert issubclass(b_class, a_class)
+        assert issubclass(c_class_1, a_class)
+        assert issubclass(c_class_1, b_class)
+        assert issubclass(c_class_2, a_class)
+        assert issubclass(c_class_2, b_class)
+        assert issubclass(d_class, a_class)
+        assert issubclass(d_class, b_class)
+        assert issubclass(d_class, c_class_2)
+
+        #-----
+        b = b_class()
+        assert b.m_a          == 1
+        assert b.m_da         == 1.1
+        assert b.m_b          == 2
+        assert b.m_db         == 2.2
+
+        b.m_a = 11
+        assert b.m_a          == 11
+        assert b.m_b          == 2
+
+        b.m_da = 11.11
+        assert b.m_da         == 11.11
+        assert b.m_db         == 2.2
+
+        b.m_b = 22
+        assert b.m_a          == 11
+        assert b.m_da         == 11.11
+        assert b.m_b          == 22
+        assert b.get_value()  == 22
+
+        b.m_db = 22.22
+        assert b.m_db         == 22.22
+
+        b.destruct()
+
+        #-----
+        c1 = c_class_1()
+        assert c1.m_a         == 1
+        assert c1.m_b         == 2
+        assert c1.m_c         == 3
+
+        c1.m_a = 11
+        assert c1.m_a         == 11
+
+        c1.m_b = 22
+        assert c1.m_a         == 11
+        assert c1.m_b         == 22
+
+        c1.m_c = 33
+        assert c1.m_a         == 11
+        assert c1.m_b         == 22
+        assert c1.m_c         == 33
+        assert c1.get_value() == 33
+
+        c1.destruct()
+
+        #-----
+        d = d_class()
+        assert d.m_a          == 1
+        assert d.m_b          == 2
+        assert d.m_c          == 3
+        assert d.m_d          == 4
+
+        d.m_a = 11
+        assert d.m_a          == 11
+
+        d.m_b = 22
+        assert d.m_a          == 11
+        assert d.m_b          == 22
+
+        d.m_c = 33
+        assert d.m_a          == 11
+        assert d.m_b          == 22
+        assert d.m_c          == 33
+
+        d.m_d = 44
+        assert d.m_a          == 11
+        assert d.m_b          == 22
+        assert d.m_c          == 33
+        assert d.m_d          == 44
+        assert d.get_value()  == 44
+
+        d.destruct()
+
+    def test07_pass_by_reference(self):
+        """Test reference passing when using virtual inheritance"""
+
+        import cppyy
+        gbl = cppyy.gbl
+        b_class = gbl.b_class
+        c_class = gbl.c_class_2
+        d_class = gbl.d_class
+
+        #-----
+        b = b_class()
+        b.m_a, b.m_b = 11, 22
+        assert gbl.get_a(b) == 11
+        assert gbl.get_b(b) == 22
+        b.destruct()
+
+        #-----
+        c = c_class()
+        c.m_a, c.m_b, c.m_c = 11, 22, 33
+        assert gbl.get_a(c) == 11
+        assert gbl.get_b(c) == 22
+        assert gbl.get_c(c) == 33
+        c.destruct()
+
+        #-----
+        d = d_class()
+        d.m_a, d.m_b, d.m_c, d.m_d = 11, 22, 33, 44
+        assert gbl.get_a(d) == 11
+        assert gbl.get_b(d) == 22
+        assert gbl.get_c(d) == 33
+        assert gbl.get_d(d) == 44
+        d.destruct()
+
+    def test08_void_pointer_passing(self):
+        """Test passing of variants of void pointer arguments"""
+
+        import cppyy
+        pointer_pass        = cppyy.gbl.pointer_pass
+        some_concrete_class = cppyy.gbl.some_concrete_class
+
+        pp = pointer_pass()
+        o = some_concrete_class()
+
+        assert cppyy.addressof(o) == pp.gime_address_ptr(o)
+        assert cppyy.addressof(o) == pp.gime_address_ptr_ptr(o)
+        assert cppyy.addressof(o) == pp.gime_address_ptr_ref(o)
+
+    def test09_opaque_pointer_assing(self):
+        """Test passing around of opaque pointers"""
+
+        import cppyy
+        some_concrete_class = cppyy.gbl.some_concrete_class
+
+        o = some_concrete_class()
+
+        #cobj = cppyy.as_cobject(o)
+        addr = cppyy.addressof(o)
+
+        #assert o == cppyy.bind_object(cobj, some_concrete_class)
+        #assert o == cppyy.bind_object(cobj, type(o))
+        #assert o == cppyy.bind_object(cobj, o.__class__)
+        #assert o == cppyy.bind_object(cobj, "some_concrete_class")
+        assert cppyy.addressof(o) == cppyy.addressof(cppyy.bind_object(addr, some_concrete_class))
+        assert o == cppyy.bind_object(addr, some_concrete_class)
+        assert o == cppyy.bind_object(addr, type(o))
+        assert o == cppyy.bind_object(addr, o.__class__)
+        #assert o == cppyy.bind_object(addr, "some_concrete_class")
+
+    def test10_object_identity(self):
+        """Test object identity"""
+
+        import cppyy
+        some_concrete_class  = cppyy.gbl.some_concrete_class
+        some_class_with_data = cppyy.gbl.some_class_with_data
+
+        o = some_concrete_class()
+        addr = cppyy.addressof(o)
+
+        o2 = cppyy.bind_object(addr, some_concrete_class)
+        assert o is o2
+
+        o3 = cppyy.bind_object(addr, some_class_with_data)
+        assert not o is o3
+
+        d1 = some_class_with_data()
+        d2 = d1.gime_copy()
+        assert not d1 is d2
+
+        dd1a = d1.gime_data()
+        dd1b = d1.gime_data()
+        assert dd1a is dd1b
+
+        dd2 = d2.gime_data()
+        assert not dd1a is dd2
+        assert not dd1b is dd2
+
+        d2.destruct()
+        d1.destruct()
+
+    def test11_multi_methods(self):
+        """Test calling of methods from multiple inheritance"""
+
+        import cppyy
+        multi = cppyy.gbl.multi
+
+        assert cppyy.gbl.multi1 is multi.__bases__[0]
+        assert cppyy.gbl.multi2 is multi.__bases__[1]
+
+        dict_keys = multi.__dict__.keys()
+        assert dict_keys.count('get_my_own_int') == 1
+        assert dict_keys.count('get_multi1_int') == 0
+        assert dict_keys.count('get_multi2_int') == 0
+
+        m = multi(1, 2, 3)
+        assert m.get_multi1_int() == 1
+        assert m.get_multi2_int() == 2
+        assert m.get_my_own_int() == 3
+
+    def test12_actual_type(self):
+        """Test that a pointer to base return does an auto-downcast"""
+
+        import cppyy
+        base_class = cppyy.gbl.base_class
+        derived_class = cppyy.gbl.derived_class
+
+        b = base_class()
+        d = derived_class()
+
+        assert b == b.cycle(b)
+        assert id(b) == id(b.cycle(b))
+        assert b == d.cycle(b)
+        assert id(b) == id(d.cycle(b))
+        assert d == b.cycle(d)
+        assert id(d) == id(b.cycle(d))
+        assert d == d.cycle(d)
+        assert id(d) == id(d.cycle(d))
+
+        assert isinstance(b.cycle(b), base_class)
+        assert isinstance(d.cycle(b), base_class)
+        assert isinstance(b.cycle(d), derived_class)
+        assert isinstance(d.cycle(d), derived_class)
+
+        assert isinstance(b.clone(), base_class)      # TODO: clone() leaks
+        assert isinstance(d.clone(), derived_class)   # TODO: clone() leaks
+
+    def test13_actual_type_virtual_multi(self):
+        """Test auto-downcast in adverse inheritance situation"""
+
+        import cppyy
+
+        c1 = cppyy.gbl.create_c1()
+        assert type(c1) == cppyy.gbl.c_class_1
+        assert c1.m_c == 3
+        c1.destruct()
+
+        if self.capi_identity == 'CINT':     # CINT does not support dynamic casts
+            return
+
+        c2 = cppyy.gbl.create_c2()
+        assert type(c2) == cppyy.gbl.c_class_2
+        assert c2.m_c == 3
+        c2.destruct()
diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_cppyy.py
@@ -0,0 +1,248 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+from pypy.module.cppyy import interp_cppyy, executor
+
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("example01Dict.so"))
+
+space = gettestobjspace(usemodules=['cppyy'])
+
+def setup_module(mod):
+    if sys.platform == 'win32':
+        py.test.skip("win32 not supported so far")
+    err = os.system("cd '%s' && make example01Dict.so" % currpath)
+    if err:
+        raise OSError("'make' failed (see stderr)")
+
+class TestCPPYYImplementation:
+    def test01_class_query(self):
+        # NOTE: this test needs to run before test_pythonify.py
+        dct = interp_cppyy.load_dictionary(space, test_dct)
+        w_cppyyclass = interp_cppyy.scope_byname(space, "example01")
+        w_cppyyclass2 = interp_cppyy.scope_byname(space, "example01")
+        assert space.is_w(w_cppyyclass, w_cppyyclass2)
+        adddouble = w_cppyyclass.methods["staticAddToDouble"]
+        func, = adddouble.functions
+        assert func.executor is None
+        func._setup(None)     # creates executor
+        assert isinstance(func.executor, executor.DoubleExecutor)
+        assert func.arg_defs == [("double", "")]
+
+
+class AppTestCPPYY:
+    def setup_class(cls):
+        cls.space = space
+        env = os.environ
+        cls.w_example01, cls.w_payload = cls.space.unpackiterable(cls.space.appexec([], """():
+            import cppyy
+            cppyy.load_reflection_info(%r)
+            return cppyy._scope_byname('example01'), cppyy._scope_byname('payload')""" % (test_dct, )))
+
+    def test01_static_int(self):
+        """Test passing of an int, returning of an int, and overloading on a
+            differening number of arguments."""
+
+        import sys, math
+        t = self.example01
+
+        res = t.get_overload("staticAddOneToInt").call(None, 1)
+        assert res == 2
+        res = t.get_overload("staticAddOneToInt").call(None, 1L)
+        assert res == 2
+        res = t.get_overload("staticAddOneToInt").call(None, 1, 2)
+        assert res == 4
+        res = t.get_overload("staticAddOneToInt").call(None, -1)
+        assert res == 0
+        maxint32 = int(2 ** 31 - 1)
+        res = t.get_overload("staticAddOneToInt").call(None, maxint32-1)
+        assert res == maxint32
+        res = t.get_overload("staticAddOneToInt").call(None, maxint32)
+        assert res == -maxint32-1
+
+        raises(TypeError, 't.get_overload("staticAddOneToInt").call(None, 1, [])')
+        raises(TypeError, 't.get_overload("staticAddOneToInt").call(None, 1.)')
+        raises(TypeError, 't.get_overload("staticAddOneToInt").call(None, maxint32+1)')
+
+    def test02_static_double(self):
+        """Test passing of a double and returning of a double on a static function."""
+
+        t = self.example01
+
+        res = t.get_overload("staticAddToDouble").call(None, 0.09)
+        assert res == 0.09 + 0.01
+
+    def test03_static_constcharp(self):
+        """Test passing of a C string and returning of a C string on a static
+            function."""
+
+        t = self.example01
+
+        res = t.get_overload("staticAtoi").call(None, "1")
+        assert res == 1
+        res = t.get_overload("staticStrcpy").call(None, "aap")       # TODO: this leaks
+        assert res == "aap"
+        res = t.get_overload("staticStrcpy").call(None, u"aap")      # TODO: this leaks
+        assert res == "aap"
+
+        raises(TypeError, 't.get_overload("staticStrcpy").call(None, 1.)')     # TODO: this leaks
+
+    def test04_method_int(self):
+        """Test passing of a int, returning of a int, and memory cleanup, on
+            a method."""
+        import cppyy
+
+        t = self.example01
+
+        assert t.get_overload("getCount").call(None) == 0
+
+        e1 = t.get_overload(t.type_name).call(None, 7)
+        assert t.get_overload("getCount").call(None) == 1
+        res = t.get_overload("addDataToInt").call(e1, 4)
+        assert res == 11
+        res = t.get_overload("addDataToInt").call(e1, -4)
+        assert res == 3
+        e1.destruct()
+        assert t.get_overload("getCount").call(None) == 0
+        raises(ReferenceError, 't.get_overload("addDataToInt").call(e1, 4)')
+
+        e1 = t.get_overload(t.type_name).call(None, 7)
+        e2 = t.get_overload(t.type_name).call(None, 8)
+        assert t.get_overload("getCount").call(None) == 2
+        e1.destruct()
+        assert t.get_overload("getCount").call(None) == 1
+        e2.destruct()
+        assert t.get_overload("getCount").call(None) == 0
+
+        e2.destruct()
+        assert t.get_overload("getCount").call(None) == 0
+
+        raises(TypeError, t.get_overload("addDataToInt").call, 41, 4)
+
+    def test05_memory(self):
+        """Test memory destruction and integrity."""
+
+        import gc
+        import cppyy
+
+        t = self.example01
+
+        assert t.get_overload("getCount").call(None) == 0
+
+        e1 = t.get_overload(t.type_name).call(None, 7)
+        assert t.get_overload("getCount").call(None) == 1
+        res = t.get_overload("addDataToInt").call(e1, 4)
+        assert res == 11
+        res = t.get_overload("addDataToInt").call(e1, -4)
+        assert res == 3
+        e1 = None
+        gc.collect()
+        assert t.get_overload("getCount").call(None) == 0
+
+        e1 = t.get_overload(t.type_name).call(None, 7)
+        e2 = t.get_overload(t.type_name).call(None, 8)
+        assert t.get_overload("getCount").call(None) == 2
+        e1 = None
+        gc.collect()
+        assert t.get_overload("getCount").call(None) == 1
+        e2.destruct()
+        assert t.get_overload("getCount").call(None) == 0
+        e2 = None
+        gc.collect()
+        assert t.get_overload("getCount").call(None) == 0
+
+    def test05a_memory2(self):
+        """Test ownership control."""
+
+        import gc, cppyy
+
+        t = self.example01
+
+        assert t.get_overload("getCount").call(None) == 0
+
+        e1 = t.get_overload(t.type_name).call(None, 7)
+        assert t.get_overload("getCount").call(None) == 1
+        assert e1._python_owns == True
+        e1._python_owns = False
+        e1 = None
+        gc.collect()
+        assert t.get_overload("getCount").call(None) == 1
+
+        # forced fix-up of object count for later tests
+        t.get_overload("setCount").call(None, 0)
+
+
+    def test06_method_double(self):
+        """Test passing of a double and returning of double on a method."""
+
+        import cppyy
+
+        t = self.example01
+
+        e = t.get_overload(t.type_name).call(None, 13)
+        res = t.get_overload("addDataToDouble").call(e, 16)
+        assert round(res-29, 8) == 0.
+        e.destruct()
+
+        e = t.get_overload(t.type_name).call(None, -13)
+        res = t.get_overload("addDataToDouble").call(e, 16)
+        assert round(res-3, 8) == 0.
+        e.destruct()
+        assert t.get_overload("getCount").call(None) == 0
+
+    def test07_method_constcharp(self):
+        """Test passing of a C string and returning of a C string on a
+            method."""
+        import cppyy
+
+        t = self.example01
+
+        e = t.get_overload(t.type_name).call(None, 42)
+        res = t.get_overload("addDataToAtoi").call(e, "13")
+        assert res == 55
+        res = t.get_overload("addToStringValue").call(e, "12")       # TODO: this leaks
+        assert res == "54"
+        res = t.get_overload("addToStringValue").call(e, "-12")      # TODO: this leaks
+        assert res == "30"
+        e.destruct()
+        assert t.get_overload("getCount").call(None) == 0
+
+    def test08_pass_object_by_pointer(self):
+        """Test passing of an instance as an argument."""
+        import cppyy
+
+        t1 = self.example01
+        t2 = self.payload
+
+        pl = t2.get_overload(t2.type_name).call(None, 3.14)
+        assert round(t2.get_overload("getData").call(pl)-3.14, 8) == 0
+        t1.get_overload("staticSetPayload").call(None, pl, 41.)      # now pl is a CPPInstance
+        assert t2.get_overload("getData").call(pl) == 41.
+
+        e = t1.get_overload(t1.type_name).call(None, 50)
+        t1.get_overload("setPayload").call(e, pl);
+        assert round(t2.get_overload("getData").call(pl)-50., 8) == 0
+
+        e.destruct()
+        pl.destruct() 
+        assert t1.get_overload("getCount").call(None) == 0
+
+    def test09_return_object_by_pointer(self):
+        """Test returning of an instance as an argument."""
+        import cppyy
+
+        t1 = self.example01
+        t2 = self.payload
+
+        pl1 = t2.get_overload(t2.type_name).call(None, 3.14)
+        assert round(t2.get_overload("getData").call(pl1)-3.14, 8) == 0
+        pl2 = t1.get_overload("staticCyclePayload").call(None, pl1, 38.)
+        assert t2.get_overload("getData").call(pl2) == 38.
+
+        e = t1.get_overload(t1.type_name).call(None, 50)
+        pl2 = t1.get_overload("cyclePayload").call(e, pl1);
+        assert round(t2.get_overload("getData").call(pl2)-50., 8) == 0
+
+        e.destruct()
+        pl1.destruct() 
+        assert t1.get_overload("getCount").call(None) == 0
diff --git a/pypy/module/cppyy/test/test_crossing.py b/pypy/module/cppyy/test/test_crossing.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_crossing.py
@@ -0,0 +1,104 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("crossingDict.so"))
+
+def setup_module(mod):
+    if sys.platform == 'win32':
+        py.test.skip("win32 not supported so far")
+    err = os.system("cd '%s' && make crossingDict.so" % currpath)
+    if err:
+        raise OSError("'make' failed (see stderr)")
+
+
+class AppTestCrossing(AppTestCpythonExtensionBase):
+    def setup_class(cls):
+        # following from AppTestCpythonExtensionBase, with cppyy added
+        cls.space = gettestobjspace(usemodules=['cpyext', 'cppyy', 'thread', '_rawffi', '_ffi', 'array'])
+        cls.space.getbuiltinmodule("cpyext")
+        from pypy.module.imp.importing import importhook
+        importhook(cls.space, "os") # warm up reference counts
+        from pypy.module.cpyext.pyobject import RefcountState
+        state = cls.space.fromcache(RefcountState)
+        state.non_heaptypes_w[:] = []
+
+        # cppyy specific additions (not that the test_dct is loaded late
+        # to allow the generated extension module be loaded first)
+        cls.w_test_dct  = cls.space.wrap(test_dct)
+        cls.w_datatypes = cls.space.appexec([], """():
+            import cppyy, cpyext""")
+
+    def setup_method(self, func):
+        AppTestCpythonExtensionBase.setup_method(self, func)
+
+        if hasattr(self, 'cmodule'):
+            return
+
+        import os, ctypes
+
+        init = """
+        if (Py_IsInitialized())
+            Py_InitModule("bar", methods);
+        """
+        body = """
+        long bar_unwrap(PyObject* arg)
+        {
+            return PyLong_AsLong(arg);
+        }
+        PyObject* bar_wrap(long l)
+        {
+            return PyLong_FromLong(l);
+        }
+        static PyMethodDef methods[] = {
+            { NULL }
+        };
+        """
+
+        modname = self.import_module(name='bar', init=init, body=body, load_it=False)
+        from pypy.module.imp.importing import get_so_extension
+        soext = get_so_extension(self.space)
+        fullmodname = os.path.join(modname, 'bar' + soext)
+        self.cmodule = ctypes.CDLL(fullmodname, ctypes.RTLD_GLOBAL)
+
+    def test00_base_class(self):
+        """Test from cpyext; only here to see whether the imported class works"""
+
+        import sys
+        init = """
+        if (Py_IsInitialized())
+            Py_InitModule("foo", NULL);
+        """
+        self.import_module(name='foo', init=init)
+        assert 'foo' in sys.modules
+
+    def test01_crossing_dict(self):
+        """Test availability of all needed classes in the dict"""
+
+        import cppyy
+        cppyy.load_reflection_info(self.test_dct)
+
+        assert cppyy.gbl.crossing == cppyy.gbl.crossing
+        crossing = cppyy.gbl.crossing
+
+        assert crossing.A == crossing.A
+
+    def test02_send_pyobject(self):
+        """Test sending a true pyobject to C++"""
+
+        import cppyy
+        crossing = cppyy.gbl.crossing
+
+        a = crossing.A()
+        assert a.unwrap(13) == 13
+
+    def test03_send_and_receive_pyobject(self):
+        """Test receiving a true pyobject from C++"""
+
+        import cppyy
+        crossing = cppyy.gbl.crossing
+
+        a = crossing.A()
+
+        assert a.wrap(41) == 41
diff --git a/pypy/module/cppyy/test/test_datatypes.py b/pypy/module/cppyy/test/test_datatypes.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_datatypes.py
@@ -0,0 +1,526 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("datatypesDict.so"))
+
+space = gettestobjspace(usemodules=['cppyy', 'array'])
+
+def setup_module(mod):
+    if sys.platform == 'win32':
+        py.test.skip("win32 not supported so far")
+    err = os.system("cd '%s' && make datatypesDict.so" % currpath)
+    if err:
+        raise OSError("'make' failed (see stderr)")
+
+class AppTestDATATYPES:
+    def setup_class(cls):
+        cls.space = space
+        env = os.environ
+        cls.w_N = space.wrap(5)    # should be imported from the dictionary
+        cls.w_test_dct  = space.wrap(test_dct)
+        cls.w_datatypes = cls.space.appexec([], """():
+            import cppyy
+            return cppyy.load_reflection_info(%r)""" % (test_dct, ))
+
+    def test01_load_reflection_cache(self):
+        """Test whether loading a refl. info twice results in the same object."""
+        import cppyy
+        lib2 = cppyy.load_reflection_info(self.test_dct)


More information about the pypy-commit mailing list