[pypy-commit] pypy default: Merged upstream.

alex_gaynor noreply at buildbot.pypy.org
Sat Jun 23 20:07:41 CEST 2012


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: 
Changeset: r55790:d8e9dbcc5c64
Date: 2012-06-23 11:07 -0700
http://bitbucket.org/pypy/pypy/changeset/d8e9dbcc5c64/

Log:	Merged upstream.

diff too long, truncating to 10000 out of 11470 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/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,7 +85,7 @@
 
     $ hg clone https://bitbucket.org/pypy/pypy
     $ cd pypy
-    $ hg up reflex-support
+    $ hg up reflex-support         # optional
     $ cd pypy/translator/goal
     $ python translate.py -O jit --gcrootfinder=shadowstack targetpypystandalone.py --withmod-cppyy
 
@@ -368,6 +371,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/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/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -8,6 +8,9 @@
 .. 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.
 
 
 .. "uninteresting" branches that we should just ignore for the whatsnew:
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/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
@@ -164,6 +164,8 @@
         data[index] = char
         array._charbuf_stop()
 
+    def get_raw_address(self):
+        return self.array._charbuf_start()
 
 def make_array(mytype):
     W_ArrayBase = globals()['W_ArrayBase']
diff --git a/pypy/module/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)
+        assert self.datatypes is lib2
+
+    def test02_instance_data_read_access(self):
+        """Test read access to instance public data and verify values"""
+
+        import cppyy, sys
+        cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+        c = cppyy_test_data()
+        assert isinstance(c, cppyy_test_data)
+
+        # reading boolean type
+        assert c.m_bool == False
+
+        # reading char types
+        assert c.m_char  == 'a'
+        assert c.m_uchar == 'c'
+
+        # reading integer types
+        assert c.m_short  == -11
+        assert c.m_ushort ==  11
+        assert c.m_int    == -22
+        assert c.m_uint   ==  22
+        assert c.m_long   == -33
+        assert c.m_ulong  ==  33
+        assert c.m_llong  == -44
+        assert c.m_ullong ==  55
+
+        # reading floating point types
+        assert round(c.m_float  + 66., 5) == 0
+        assert round(c.m_double + 77., 8) == 0
+
+        # reding of array types
+        for i in range(self.N):
+            # reading of integer array types
+            assert c.m_short_array[i]       ==  -1*i
+            assert c.get_short_array()[i]   ==  -1*i
+            assert c.m_short_array2[i]      ==  -2*i
+            assert c.get_short_array2()[i]  ==  -2*i
+            assert c.m_ushort_array[i]      ==   3*i
+            assert c.get_ushort_array()[i]  ==   3*i
+            assert c.m_ushort_array2[i]     ==   4*i
+            assert c.get_ushort_array2()[i] ==   4*i
+            assert c.m_int_array[i]         ==  -5*i
+            assert c.get_int_array()[i]     ==  -5*i
+            assert c.m_int_array2[i]        ==  -6*i
+            assert c.get_int_array2()[i]    ==  -6*i
+            assert c.m_uint_array[i]        ==   7*i
+            assert c.get_uint_array()[i]    ==   7*i
+            assert c.m_uint_array2[i]       ==   8*i
+            assert c.get_uint_array2()[i]   ==   8*i
+
+            assert c.m_long_array[i]        ==  -9*i
+            assert c.get_long_array()[i]    ==  -9*i
+            assert c.m_long_array2[i]       == -10*i
+            assert c.get_long_array2()[i]   == -10*i
+            assert c.m_ulong_array[i]       ==  11*i
+            assert c.get_ulong_array()[i]   ==  11*i
+            assert c.m_ulong_array2[i]      ==  12*i
+            assert c.get_ulong_array2()[i]  ==  12*i
+
+            assert round(c.m_float_array[i]   + 13.*i, 5) == 0
+            assert round(c.m_float_array2[i]  + 14.*i, 5) == 0
+            assert round(c.m_double_array[i]  + 15.*i, 8) == 0
+            assert round(c.m_double_array2[i] + 16.*i, 8) == 0
+
+        # out-of-bounds checks
+        raises(IndexError, c.m_short_array.__getitem__,  self.N)
+        raises(IndexError, c.m_ushort_array.__getitem__, self.N)
+        raises(IndexError, c.m_int_array.__getitem__,    self.N)
+        raises(IndexError, c.m_uint_array.__getitem__,   self.N)
+        raises(IndexError, c.m_long_array.__getitem__,   self.N)
+        raises(IndexError, c.m_ulong_array.__getitem__,  self.N)
+        raises(IndexError, c.m_float_array.__getitem__,  self.N)
+        raises(IndexError, c.m_double_array.__getitem__, self.N)
+
+        c.destruct()
+
+    def test03_instance_data_write_access(self):
+        """Test write access to instance public data and verify values"""
+
+        import cppyy, sys
+        cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+        c = cppyy_test_data()
+        assert isinstance(c, cppyy_test_data)
+
+        # boolean types through functions
+        c.set_bool(True);
+        assert c.get_bool() == True
+        c.set_bool(0);     assert c.get_bool() == False
+
+        # boolean types through data members
+        c.m_bool = True;   assert c.get_bool() == True
+        c.set_bool(True);  assert c.m_bool     == True
+        c.m_bool = 0;      assert c.get_bool() == False
+        c.set_bool(0);     assert c.m_bool     == False
+
+        raises(TypeError, 'c.set_bool(10)')
+
+        # char types through functions
+        c.set_char('c');   assert c.get_char()  == 'c'
+        c.set_uchar('e');  assert c.get_uchar() == 'e'
+
+        # char types through data members
+        c.m_char = 'b';    assert c.get_char()  ==     'b'
+        c.m_char = 40;     assert c.get_char()  == chr(40)
+        c.set_char('c');   assert c.m_char      ==     'c'
+        c.set_char(41);    assert c.m_char      == chr(41)
+        c.m_uchar = 'd';   assert c.get_uchar() ==     'd'
+        c.m_uchar = 42;    assert c.get_uchar() == chr(42)
+        c.set_uchar('e');  assert c.m_uchar     ==     'e'
+        c.set_uchar(43);   assert c.m_uchar     == chr(43)
+
+        raises(TypeError, 'c.set_char("string")')
+        raises(TypeError, 'c.set_char(500)')
+        raises(TypeError, 'c.set_uchar("string")')
+# TODO: raises(TypeError, 'c.set_uchar(-1)')
+
+        # integer types
+        names = ['short', 'ushort', 'int', 'uint', 'long', 'ulong', 'llong', 'ullong']
+        for i in range(len(names)):
+            exec 'c.m_%s = %d' % (names[i],i)
+            assert eval('c.get_%s()' % names[i]) == i
+
+        for i in range(len(names)):
+            exec 'c.set_%s(%d)' % (names[i],2*i)
+            assert eval('c.m_%s' % names[i]) == 2*i
+
+        for i in range(len(names)):
+            exec 'c.set_%s_c(%d)' % (names[i],3*i)
+            assert eval('c.m_%s' % names[i]) == 3*i
+
+        # float types through functions
+        c.set_float( 0.123 );  assert round(c.get_float()  - 0.123, 5) == 0
+        c.set_double( 0.456 ); assert round(c.get_double() - 0.456, 8) == 0
+
+        # float types through data members
+        c.m_float = 0.123;     assert round(c.get_float()  - 0.123, 5) == 0
+        c.set_float(0.234);    assert round(c.m_float      - 0.234, 5) == 0
+        c.set_float_c(0.456);  assert round(c.m_float      - 0.456, 5) == 0
+        c.m_double = 0.678;    assert round(c.get_double() - 0.678, 8) == 0
+        c.set_double(0.890);   assert round(c.m_double     - 0.890, 8) == 0
+        c.set_double_c(0.012); assert round(c.m_double     - 0.012, 8) == 0
+
+        # arrays; there will be pointer copies, so destroy the current ones
+        c.destroy_arrays()
+
+        # integer arrays
+        names = ['short', 'ushort', 'int', 'uint', 'long', 'ulong']
+        import array
+        a = range(self.N)
+        atypes = ['h', 'H', 'i', 'I', 'l', 'L' ]
+        for j in range(len(names)):
+            b = array.array(atypes[j], a)
+            exec 'c.m_%s_array = b' % names[j]   # buffer copies
+            for i in range(self.N):
+                assert eval('c.m_%s_array[i]' % names[j]) == b[i]
+
+            exec 'c.m_%s_array2 = b' % names[j]  # pointer copies
+            b[i] = 28
+            for i in range(self.N):
+                assert eval('c.m_%s_array2[i]' % names[j]) == b[i]
+
+        c.destruct()
+
+    def test04_respect_privacy(self):
+        """Test that privacy settings are respected"""
+
+        import cppyy
+        cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+        c = cppyy_test_data()
+        assert isinstance(c, cppyy_test_data)
+
+        raises(AttributeError, getattr, c, 'm_owns_arrays')
+
+        c.destruct()
+
+    def test05_class_read_access(self):
+        """Test read access to class public data and verify values"""
+
+        import cppyy, sys
+        cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+        c = cppyy_test_data()
+        assert isinstance(c, cppyy_test_data)
+
+        # char types
+        assert cppyy_test_data.s_char  == 's'
+        assert c.s_char                == 's'
+        assert c.s_uchar               == 'u'
+        assert cppyy_test_data.s_uchar == 'u'
+
+        # integer types
+        assert cppyy_test_data.s_short  == -101
+        assert c.s_short                == -101
+        assert c.s_ushort               ==  255
+        assert cppyy_test_data.s_ushort ==  255
+        assert cppyy_test_data.s_int    == -202
+        assert c.s_int                  == -202
+        assert c.s_uint                 ==  202
+        assert cppyy_test_data.s_uint   ==  202
+        assert cppyy_test_data.s_long   == -303L
+        assert c.s_long                 == -303L
+        assert c.s_ulong                ==  303L
+        assert cppyy_test_data.s_ulong  ==  303L
+        assert cppyy_test_data.s_llong  == -404L
+        assert c.s_llong                == -404L
+        assert c.s_ullong               ==  505L
+        assert cppyy_test_data.s_ullong ==  505L
+
+        # floating point types
+        assert round(cppyy_test_data.s_float  + 606., 5) == 0
+        assert round(c.s_float                + 606., 5) == 0
+        assert round(cppyy_test_data.s_double + 707., 8) == 0
+        assert round(c.s_double               + 707., 8) == 0
+
+        c.destruct()
+
+    def test06_class_data_write_access(self):
+        """Test write access to class public data and verify values"""
+
+        import cppyy, sys
+        cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+        c = cppyy_test_data()
+        assert isinstance(c, cppyy_test_data)
+
+        # char types
+        cppyy_test_data.s_char          = 'a'
+        assert c.s_char                == 'a'
+        c.s_char                        = 'b'
+        assert cppyy_test_data.s_char  == 'b'
+        cppyy_test_data.s_uchar         = 'c'
+        assert c.s_uchar               == 'c'
+        c.s_uchar                       = 'd'
+        assert cppyy_test_data.s_uchar == 'd'
+        raises(ValueError, setattr, cppyy_test_data, 's_uchar', -1)
+        raises(ValueError, setattr, c,               's_uchar', -1)
+
+        # integer types
+        c.s_short                        = -102
+        assert cppyy_test_data.s_short  == -102
+        cppyy_test_data.s_short          = -203
+        assert c.s_short                == -203
+        c.s_ushort                       =  127
+        assert cppyy_test_data.s_ushort ==  127
+        cppyy_test_data.s_ushort         =  227
+        assert c.s_ushort               ==  227
+        cppyy_test_data.s_int            = -234
+        assert c.s_int                  == -234
+        c.s_int                          = -321
+        assert cppyy_test_data.s_int    == -321
+        cppyy_test_data.s_uint           = 1234
+        assert c.s_uint                 == 1234
+        c.s_uint                         = 4321
+        assert cppyy_test_data.s_uint   == 4321
+        raises(ValueError, setattr, c,               's_uint', -1)
+        raises(ValueError, setattr, cppyy_test_data, 's_uint', -1)
+        cppyy_test_data.s_long           = -87L
+        assert c.s_long                 == -87L
+        c.s_long                         = 876L
+        assert cppyy_test_data.s_long   == 876L
+        cppyy_test_data.s_ulong          = 876L
+        assert c.s_ulong                == 876L
+        c.s_ulong                        = 678L
+        assert cppyy_test_data.s_ulong  == 678L
+        raises(ValueError, setattr, cppyy_test_data, 's_ulong', -1)
+        raises(ValueError, setattr, c,               's_ulong', -1)
+
+        # floating point types
+        cppyy_test_data.s_float                    = -3.1415
+        assert round(c.s_float, 5 )               == -3.1415
+        c.s_float                                  =  3.1415
+        assert round(cppyy_test_data.s_float, 5 ) ==  3.1415
+        import math
+        c.s_double                                 = -math.pi
+        assert cppyy_test_data.s_double           == -math.pi
+        cppyy_test_data.s_double                   =  math.pi
+        assert c.s_double                         ==  math.pi
+
+        c.destruct()
+
+    def test07_range_access(self):
+        """Test the ranges of integer types"""
+
+        import cppyy, sys
+        cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+        c = cppyy_test_data()
+        assert isinstance(c, cppyy_test_data)
+
+        # TODO: should these be TypeErrors, or should char/bool raise
+        #       ValueErrors? In any case, consistency is needed ...
+        raises(ValueError, setattr, c, 'm_uint',  -1)
+        raises(ValueError, setattr, c, 'm_ulong', -1)
+
+        c.destruct()
+
+    def test08_type_conversions(self):
+        """Test conversions between builtin types"""
+
+        import cppyy, sys
+        cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+        c = cppyy_test_data()
+        assert isinstance(c, cppyy_test_data)
+
+        c.m_double = -1
+        assert round(c.m_double + 1.0, 8) == 0
+
+        raises(TypeError, c.m_double,  'c')
+        raises(TypeError, c.m_int,     -1.)
+        raises(TypeError, c.m_int,      1.)
+
+        c.destruct()
+
+    def test09_global_builtin_type(self):
+        """Test access to a global builtin type"""
+
+        import cppyy
+        gbl = cppyy.gbl
+
+        assert gbl.g_int == gbl.get_global_int()
+
+        gbl.set_global_int(32)
+        assert gbl.get_global_int() == 32
+        assert gbl.g_int == 32
+
+        gbl.g_int = 22
+        assert gbl.get_global_int() == 22
+        assert gbl.g_int == 22
+
+    def test10_global_ptr(self):
+        """Test access of global objects through a pointer"""
+
+        import cppyy
+        gbl = cppyy.gbl
+
+        raises(ReferenceError, 'gbl.g_pod.m_int')
+
+        c = gbl.cppyy_test_pod()
+        c.m_int = 42
+        c.m_double = 3.14
+
+        gbl.set_global_pod(c)
+        assert gbl.is_global_pod(c)
+        assert gbl.g_pod.m_int == 42
+        assert gbl.g_pod.m_double == 3.14
+
+        d = gbl.get_global_pod()
+        assert gbl.is_global_pod(d)
+        assert c == d
+        assert id(c) == id(d)
+
+        e = gbl.cppyy_test_pod()
+        e.m_int = 43
+        e.m_double = 2.14
+
+        gbl.g_pod = e
+        assert gbl.is_global_pod(e)
+        assert gbl.g_pod.m_int == 43
+        assert gbl.g_pod.m_double == 2.14
+
+    def test11_enum(self):
+        """Test access to enums"""
+
+        import cppyy
+        gbl = cppyy.gbl
+
+        cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+        c = cppyy_test_data()
+        assert isinstance(c, cppyy_test_data)
+
+        # TODO: test that the enum is accessible as a type
+
+        assert cppyy_test_data.kNothing   ==   6
+        assert cppyy_test_data.kSomething == 111
+        assert cppyy_test_data.kLots      ==  42
+
+        assert c.get_enum() == cppyy_test_data.kNothing
+        assert c.m_enum == cppyy_test_data.kNothing
+
+        c.m_enum = cppyy_test_data.kSomething
+        assert c.get_enum() == cppyy_test_data.kSomething
+        assert c.m_enum == cppyy_test_data.kSomething
+
+        c.set_enum(cppyy_test_data.kLots)
+        assert c.get_enum() == cppyy_test_data.kLots
+        assert c.m_enum == cppyy_test_data.kLots
+
+        assert c.s_enum == cppyy_test_data.s_enum
+        assert c.s_enum == cppyy_test_data.kNothing
+        assert cppyy_test_data.s_enum == cppyy_test_data.kNothing
+
+        c.s_enum = cppyy_test_data.kSomething
+        assert c.s_enum == cppyy_test_data.s_enum
+        assert c.s_enum == cppyy_test_data.kSomething
+        assert cppyy_test_data.s_enum == cppyy_test_data.kSomething
+
+    def test12_object_returns(self):
+        """Test access to and return of PODs"""
+
+        import cppyy
+
+        c = cppyy.gbl.cppyy_test_data()
+
+        assert c.m_pod.m_int == 888
+        assert c.m_pod.m_double == 3.14
+
+        pod = c.get_pod_val()
+        assert pod.m_int == 888
+        assert pod.m_double == 3.14
+
+        assert c.get_pod_ptr().m_int == 888
+        assert c.get_pod_ptr().m_double == 3.14
+        c.get_pod_ptr().m_int = 777
+        assert c.get_pod_ptr().m_int == 777
+
+        assert c.get_pod_ref().m_int == 777
+        assert c.get_pod_ref().m_double == 3.14
+        c.get_pod_ref().m_int = 666
+        assert c.get_pod_ref().m_int == 666
+
+        assert c.get_pod_ptrref().m_int == 666
+        assert c.get_pod_ptrref().m_double == 3.14
+
+    def test13_object_arguments(self):
+        """Test setting and returning of a POD through arguments"""
+
+        import cppyy
+
+        c = cppyy.gbl.cppyy_test_data()
+        assert c.m_pod.m_int == 888
+        assert c.m_pod.m_double == 3.14
+
+        p = cppyy.gbl.cppyy_test_pod()
+        p.m_int = 123
+        assert p.m_int == 123
+        p.m_double = 321.
+        assert p.m_double == 321.
+
+        c.set_pod_val(p)
+        assert c.m_pod.m_int == 123
+        assert c.m_pod.m_double == 321.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_ptr_in(p)
+        assert c.m_pod.m_int == 123
+        assert c.m_pod.m_double == 321.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_ptr_out(p)
+        assert p.m_int == 888
+        assert p.m_double == 3.14
+
+        p.m_int = 555
+        p.m_double = 666.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_ref(p)
+        assert c.m_pod.m_int == 555
+        assert c.m_pod.m_double == 666.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_ptrptr_in(p)
+        assert c.m_pod.m_int == 555
+        assert c.m_pod.m_double == 666.
+        assert p.m_int == 555
+        assert p.m_double == 666.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_void_ptrptr_in(p)
+        assert c.m_pod.m_int == 555
+        assert c.m_pod.m_double == 666.
+        assert p.m_int == 555
+        assert p.m_double == 666.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_ptrptr_out(p)
+        assert c.m_pod.m_int == 888
+        assert c.m_pod.m_double == 3.14
+        assert p.m_int == 888
+        assert p.m_double == 3.14
+
+        p.m_int = 777
+        p.m_double = 888.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_void_ptrptr_out(p)
+        assert c.m_pod.m_int == 888
+        assert c.m_pod.m_double == 3.14
+        assert p.m_int == 888
+        assert p.m_double == 3.14
diff --git a/pypy/module/cppyy/test/test_fragile.py b/pypy/module/cppyy/test/test_fragile.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_fragile.py
@@ -0,0 +1,196 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("fragileDict.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 fragileDict.so" % currpath)
+    if err:
+        raise OSError("'make' failed (see stderr)")
+
+class AppTestFRAGILE:
+    def setup_class(cls):
+        cls.space = space
+        env = os.environ
+        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_failure(self):
+        """Test failure to load dictionary"""
+
+        import cppyy
+        raises(RuntimeError, cppyy.load_reflection_info, "does_not_exist.so")
+
+    def test02_missing_classes(self):
+        """Test (non-)access to missing classes"""
+
+        import cppyy
+
+        raises(AttributeError, getattr, cppyy.gbl, "no_such_class")
+
+        assert cppyy.gbl.fragile == cppyy.gbl.fragile
+        fragile = cppyy.gbl.fragile
+
+        raises(AttributeError, getattr, fragile, "no_such_class")
+
+        assert fragile.C == fragile.C
+        assert fragile.C().check() == ord('C')
+
+        assert fragile.B == fragile.B
+        assert fragile.B().check() == ord('B')
+        raises(TypeError, fragile.B().gime_no_such)
+
+        assert fragile.C == fragile.C
+        assert fragile.C().check() == ord('C')
+        raises(TypeError, fragile.C().use_no_such, None)
+
+    def test03_arguments(self):
+        """Test reporting when providing wrong arguments"""
+
+        import cppyy
+
+        assert cppyy.gbl.fragile == cppyy.gbl.fragile
+        fragile = cppyy.gbl.fragile
+
+        assert fragile.D == fragile.D
+        assert fragile.D().check() == ord('D')
+
+        d = fragile.D()
+        raises(TypeError, d.overload, None)
+        raises(TypeError, d.overload, None, None, None)
+
+        d.overload('a')
+        d.overload(1)
+
+    def test04_unsupported_arguments(self):
+        """Test arguments that are yet unsupported"""
+
+        import cppyy
+
+        assert cppyy.gbl.fragile == cppyy.gbl.fragile
+        fragile = cppyy.gbl.fragile
+
+        assert fragile.E == fragile.E
+        assert fragile.E().check() == ord('E')
+
+        e = fragile.E()
+        raises(TypeError, e.overload, None)
+        raises(TypeError, getattr, e, 'm_pp_no_such')
+
+    def test05_wrong_arg_addressof(self):
+        """Test addressof() error reporting"""
+
+        import cppyy
+
+        assert cppyy.gbl.fragile == cppyy.gbl.fragile
+        fragile = cppyy.gbl.fragile
+
+        assert fragile.F == fragile.F
+        assert fragile.F().check() == ord('F')
+
+        f = fragile.F()
+        o = object()
+
+        cppyy.addressof(f)
+        raises(TypeError, cppyy.addressof, o)
+        raises(TypeError, cppyy.addressof, 0)
+        raises(TypeError, cppyy.addressof, 1)
+        raises(TypeError, cppyy.addressof, None)
+
+    def test06_wrong_this(self):
+        """Test that using an incorrect self argument raises"""
+
+        import cppyy
+
+        assert cppyy.gbl.fragile == cppyy.gbl.fragile
+        fragile = cppyy.gbl.fragile
+
+        a = fragile.A()
+        assert fragile.A.check(a) == ord('A')
+
+        b = fragile.B()
+        assert fragile.B.check(b) == ord('B')
+        raises(TypeError, fragile.A.check, b)
+        raises(TypeError, fragile.B.check, a)
+
+        assert not a.gime_null()
+
+        assert isinstance(a.gime_null(), fragile.A)
+        raises(ReferenceError, fragile.A.check, a.gime_null())
+
+    def test07_unnamed_enum(self):
+        """Test that an unnamed enum does not cause infinite recursion"""
+
+        import cppyy
+
+        assert cppyy.gbl.fragile is cppyy.gbl.fragile
+        fragile = cppyy.gbl.fragile
+        assert cppyy.gbl.fragile is fragile
+
+        g = fragile.G()
+
+    def test08_unhandled_scoped_datamember(self):
+        """Test that an unhandled scoped data member does not cause infinite recursion"""
+
+        import cppyy
+
+        assert cppyy.gbl.fragile is cppyy.gbl.fragile
+        fragile = cppyy.gbl.fragile
+        assert cppyy.gbl.fragile is fragile
+
+        h = fragile.H()
+
+    def test09_operator_bool(self):
+        """Access to global vars with an operator bool() returning False"""
+
+        import cppyy
+
+        i = cppyy.gbl.fragile.I()
+        assert not i
+
+        g = cppyy.gbl.fragile.gI
+        assert not g
+
+    def test10_documentation(self):
+        """Check contents of documentation"""
+
+        import cppyy
+
+        assert cppyy.gbl.fragile == cppyy.gbl.fragile
+        fragile = cppyy.gbl.fragile
+
+        d = fragile.D()
+        try:
+            d.check(None)         # raises TypeError
+            assert 0
+        except TypeError, e:
+            assert "fragile::D::check()" in str(e)
+            assert "TypeError: wrong number of arguments" in str(e)
+
+        try:
+            d.overload(None)      # raises TypeError
+            assert 0
+        except TypeError, e:
+            assert "fragile::D::overload()" in str(e)
+            assert "TypeError: wrong number of arguments" in str(e)
+            assert "fragile::D::overload(fragile::no_such_class*)" in str(e)
+            assert "TypeError: no converter available for type \"fragile::no_such_class*\"" in str(e)
+            assert "fragile::D::overload(char, int)" in str(e)
+            assert "TypeError: expected string, got NoneType object" in str(e)
+            assert "fragile::D::overload(int, fragile::no_such_class*)" in str(e)
+            assert "TypeError: unsupported operand type for int(): 'NoneType'" in str(e)
+
+        j = fragile.J()
+        assert fragile.J.method1.__doc__ == j.method1.__doc__
+        assert j.method1.__doc__ == "int fragile::J::method1(int, double)"
+
+        f = fragile.fglobal
+        assert f.__doc__ == "void fragile::fglobal(int, double, char)"
diff --git a/pypy/module/cppyy/test/test_helper.py b/pypy/module/cppyy/test/test_helper.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_helper.py
@@ -0,0 +1,44 @@
+from pypy.module.cppyy import helper
+
+def test_remove_const():
+    assert helper.remove_const("const int") == "int"
+
+def test_compound():
+    assert helper.compound("int*") == "*"
+    assert helper.compound("int* const *&") == "**&"
+    assert helper.compound("std::vector<int>*") == "*"
+    assert helper.compound("unsigned long int[5]") == "[]"
+    assert helper.array_size("unsigned long int[5]") == 5
+
+
+def test_array_size():
+    assert helper.array_size("int[5]") == 5
+
+
+def test_clean_type():
+    assert helper.clean_type(" int***") == "int"
+    assert helper.clean_type("int* const *&") == "int"
+    assert helper.clean_type("std::vector<int>&") == "std::vector<int>"
+    assert helper.clean_type("const std::vector<int>&") == "std::vector<int>"
+    assert helper.clean_type("std::vector<std::vector<int> >" ) == "std::vector<std::vector<int> >"
+    assert helper.clean_type("unsigned short int[3]") == "unsigned short int"
+
+
+def test_operator_mapping():
+    assert helper.map_operator_name("operator[]", 1, "const int&")  == "__getitem__"
+    assert helper.map_operator_name("operator[]", 1, "int&")        == "__setitem__"
+
+    assert helper.map_operator_name("operator()", 1, "")  == "__call__"
+    assert helper.map_operator_name("operator%", 1, "")   == "__mod__"
+    assert helper.map_operator_name("operator**", 1, "")  == "__pow__"
+    assert helper.map_operator_name("operator<<", 1, "")  == "__lshift__"
+    assert helper.map_operator_name("operator|", 1, "")   == "__or__"
+
+    assert helper.map_operator_name("operator*", 1, "") == "__mul__"
+    assert helper.map_operator_name("operator*", 0, "") == "__deref__"
+
+    assert helper.map_operator_name("operator+", 1, "") == "__add__"
+    assert helper.map_operator_name("operator+", 0, "") == "__pos__"
+
+    assert helper.map_operator_name("func", 0, "")        == "func"
+    assert helper.map_operator_name("some_method", 0, "") == "some_method"
diff --git a/pypy/module/cppyy/test/test_operators.py b/pypy/module/cppyy/test/test_operators.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_operators.py
@@ -0,0 +1,141 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("operatorsDict.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 operatorsDict.so" % currpath)
+    if err:
+        raise OSError("'make' failed (see stderr)")
+
+class AppTestOPERATORS:
+    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_operators = cls.space.appexec([], """():
+            import cppyy
+            return cppyy.load_reflection_info(%r)""" % (test_dct, ))
+
+    def teardown_method(self, meth):
+        import gc
+        gc.collect()
+
+    def test01_math_operators(self):
+        """Test overloading of math operators"""
+
+        import cppyy
+        number = cppyy.gbl.number
+
+        assert (number(20) + number(10)) == number(30)
+        assert (number(20) + 10        ) == number(30)
+        assert (number(20) - number(10)) == number(10)
+        assert (number(20) - 10        ) == number(10)
+        assert (number(20) / number(10)) == number(2)
+        assert (number(20) / 10        ) == number(2)
+        assert (number(20) * number(10)) == number(200)
+        assert (number(20) * 10        ) == number(200)
+        assert (number(20) % 10        ) == number(0)
+        assert (number(20) % number(10)) == number(0)
+        assert (number(5)  & number(14)) == number(4)
+        assert (number(5)  | number(14)) == number(15)
+        assert (number(5)  ^ number(14)) == number(11)
+        assert (number(5)  << 2) == number(20)
+        assert (number(20) >> 2) == number(5)
+
+    def test02_unary_math_operators(self):
+        """Test overloading of unary math operators"""
+
+        import cppyy
+        number = cppyy.gbl.number
+
+        n  = number(20)
+        n += number(10)
+        n -= number(10)
+        n *= number(10)
+        n /= number(2)
+        assert n == number(100)
+
+        nn = -n;
+        assert nn == number(-100)
+
+    def test03_comparison_operators(self):
+        """Test overloading of comparison operators"""
+
+        import cppyy
+        number = cppyy.gbl.number
+
+        assert (number(20) >  number(10)) == True
+        assert (number(20) <  number(10)) == False
+        assert (number(20) >= number(20)) == True
+        assert (number(20) <= number(10)) == False
+        assert (number(20) != number(10)) == True
+        assert (number(20) == number(10)) == False
+
+    def test04_boolean_operator(self):
+        """Test implementation of operator bool"""
+
+        import cppyy
+        number = cppyy.gbl.number
+
+        n = number(20)
+        assert n
+
+        n = number(0)
+        assert not n
+
+    def test05_exact_types(self):
+        """Test converter operators of exact types"""
+
+        import cppyy
+        gbl = cppyy.gbl
+
+        o = gbl.operator_char_star()
+        assert o.m_str == 'operator_char_star'
+        assert str(o)  == 'operator_char_star'
+
+        o = gbl.operator_const_char_star()
+        assert o.m_str == 'operator_const_char_star'
+        assert str(o)  == 'operator_const_char_star'
+
+        o = gbl.operator_int(); o.m_int = -13
+        assert o.m_int == -13
+        assert int(o)  == -13
+
+        o = gbl.operator_long(); o.m_long = 42


More information about the pypy-commit mailing list