[pypy-commit] pypy stm-thread: hg merge default

arigo noreply at buildbot.pypy.org
Fri Jul 27 14:38:12 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: stm-thread
Changeset: r56489:f88c21dc1288
Date: 2012-07-26 09:56 +0000
http://bitbucket.org/pypy/pypy/changeset/f88c21dc1288/

Log:	hg merge default

diff too long, truncating to 10000 out of 22920 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/ctypes_configure/cbuild.py b/ctypes_configure/cbuild.py
--- a/ctypes_configure/cbuild.py
+++ b/ctypes_configure/cbuild.py
@@ -372,7 +372,7 @@
         self.library_dirs = list(eci.library_dirs)
         self.compiler_exe = compiler_exe
         self.profbased = profbased
-        if not sys.platform in ('win32', 'darwin'): # xxx
+        if not sys.platform in ('win32', 'darwin', 'cygwin'): # xxx
             if 'm' not in self.libraries:
                 self.libraries.append('m')
             if 'pthread' not in self.libraries:
diff --git a/lib-python/2.7/distutils/sysconfig_pypy.py b/lib-python/2.7/distutils/sysconfig_pypy.py
--- a/lib-python/2.7/distutils/sysconfig_pypy.py
+++ b/lib-python/2.7/distutils/sysconfig_pypy.py
@@ -39,11 +39,10 @@
     If 'prefix' is supplied, use it instead of sys.prefix or
     sys.exec_prefix -- i.e., ignore 'plat_specific'.
     """
-    if standard_lib:
-        raise DistutilsPlatformError(
-            "calls to get_python_lib(standard_lib=1) cannot succeed")
     if prefix is None:
         prefix = PREFIX
+    if standard_lib:
+        return os.path.join(prefix, "lib-python", get_python_version())
     return os.path.join(prefix, 'site-packages')
 
 
diff --git a/lib-python/stdlib-upgrade.txt b/lib-python/stdlib-upgrade.txt
new file mode 100644
--- /dev/null
+++ b/lib-python/stdlib-upgrade.txt
@@ -0,0 +1,19 @@
+Process for upgrading the stdlib to a new cpython version
+==========================================================
+
+.. note::
+
+    overly detailed
+
+1. check out the branch vendor/stdlib
+2. upgrade the files there
+3. update stdlib-versions.txt with the output of hg -id from the cpython repo
+4. commit
+5. update to default/py3k
+6. create a integration branch for the new stdlib
+   (just hg branch stdlib-$version)
+7. merge vendor/stdlib
+8. commit
+10. fix issues
+11. commit --close-branch
+12. merge to default
diff --git a/lib_pypy/PyQt4.py b/lib_pypy/PyQt4.py
deleted file mode 100644
--- a/lib_pypy/PyQt4.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from _rpyc_support import proxy_sub_module, remote_eval
-
-
-for name in ("QtCore", "QtGui", "QtWebKit"):
-    proxy_sub_module(globals(), name)
-
-s = "__import__('PyQt4').QtGui.QDialogButtonBox."
-QtGui.QDialogButtonBox.Cancel = remote_eval("%sCancel | %sCancel" % (s, s))
-QtGui.QDialogButtonBox.Ok = remote_eval("%sOk | %sOk" % (s, s))
diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py
--- a/lib_pypy/_ctypes/primitive.py
+++ b/lib_pypy/_ctypes/primitive.py
@@ -249,6 +249,13 @@
                 self._buffer[0] = value
             result.value = property(_getvalue, _setvalue)
 
+        elif tp == '?':  # regular bool
+            def _getvalue(self):
+                return bool(self._buffer[0])
+            def _setvalue(self, value):
+                self._buffer[0] = bool(value)
+            result.value = property(_getvalue, _setvalue)
+
         elif tp == 'v': # VARIANT_BOOL type
             def _getvalue(self):
                 return bool(self._buffer[0])
diff --git a/lib_pypy/_rpyc_support.py b/lib_pypy/_rpyc_support.py
deleted file mode 100644
--- a/lib_pypy/_rpyc_support.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import sys
-import socket
-
-from rpyc import connect, SlaveService
-from rpyc.utils.classic import DEFAULT_SERVER_PORT
-
-try:
-    conn = connect("localhost", DEFAULT_SERVER_PORT, SlaveService,
-           config=dict(call_by_value_for_builtin_mutable_types=True))
-except socket.error, e:
-    raise ImportError("Error while connecting: " + str(e))
-
-
-remote_eval = conn.eval
-
-
-def proxy_module(globals):
-    module = getattr(conn.modules, globals["__name__"])
-    for name in module.__dict__.keys():
-        globals[name] = getattr(module, name)
-
-def proxy_sub_module(globals, name):
-    fullname = globals["__name__"] + "." + name
-    sys.modules[fullname] = globals[name] = conn.modules[fullname]
diff --git a/lib_pypy/disassembler.py b/lib_pypy/disassembler.py
--- a/lib_pypy/disassembler.py
+++ b/lib_pypy/disassembler.py
@@ -24,6 +24,11 @@
         self.lineno = lineno
         self.line_starts_here = False
 
+    def __str__(self):
+        if self.arg is None:
+            return "%s" % (self.__class__.__name__,)
+        return "%s (%s)" % (self.__class__.__name__, self.arg)
+
     def __repr__(self):
         if self.arg is None:
             return "<%s at %d>" % (self.__class__.__name__, self.pos)
diff --git a/lib_pypy/distributed/__init__.py b/lib_pypy/distributed/__init__.py
deleted file mode 100644
--- a/lib_pypy/distributed/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-
-try:
-    from protocol import RemoteProtocol, test_env, remote_loop, ObjectNotFound
-except ImportError:
-    # XXX fix it
-    # UGH. This is needed for tests
-    pass
diff --git a/lib_pypy/distributed/demo/sockdemo.py b/lib_pypy/distributed/demo/sockdemo.py
deleted file mode 100644
--- a/lib_pypy/distributed/demo/sockdemo.py
+++ /dev/null
@@ -1,42 +0,0 @@
-
-from distributed import RemoteProtocol, remote_loop
-from distributed.socklayer import Finished, socket_listener, socket_connecter
-
-PORT = 12122
-
-class X:
-    def __init__(self, z):
-        self.z = z
-        
-    def meth(self, x):
-        return self.z + x()
-
-    def raising(self):
-        1/0
-
-x = X(3)
-
-def remote():
-    send, receive = socket_listener(address=('', PORT))
-    remote_loop(RemoteProtocol(send, receive, globals()))
-
-def local():
-    send, receive = socket_connecter(('localhost', PORT))
-    return RemoteProtocol(send, receive)
-
-import sys
-if __name__ == '__main__':
-    if len(sys.argv) > 1 and sys.argv[1] == '-r':
-        try:
-            remote()
-        except Finished:
-            print "Finished"
-    else:
-        rp = local()
-        x = rp.get_remote("x")
-        try:
-            x.raising()
-        except:
-            import sys
-            import pdb
-            pdb.post_mortem(sys.exc_info()[2])
diff --git a/lib_pypy/distributed/faker.py b/lib_pypy/distributed/faker.py
deleted file mode 100644
--- a/lib_pypy/distributed/faker.py
+++ /dev/null
@@ -1,89 +0,0 @@
-
-""" This file is responsible for faking types
-"""
-
-class GetSetDescriptor(object):
-    def __init__(self, protocol, name):
-        self.protocol = protocol
-        self.name = name
-
-    def __get__(self, obj, type=None):
-        return self.protocol.get(self.name, obj, type)
-
-    def __set__(self, obj, value):
-        self.protocol.set(self.name, obj, value)
-
-class GetDescriptor(object):
-    def __init__(self, protocol, name):
-        self.protocol = protocol
-        self.name = name
-
-    def __get__(self, obj, type=None):
-        return self.protocol.get(self.name, obj, type)
-
-# these are one-go functions for wrapping/unwrapping types,
-# note that actual caching is defined in other files,
-# this is only the case when we *need* to wrap/unwrap
-# type
-
-from types import MethodType, FunctionType
-
-def not_ignore(name):
-    # we don't want to fake some default descriptors, because
-    # they'll alter the way we set attributes
-    l = ['__dict__', '__weakref__', '__class__', '__bases__',
-         '__getattribute__', '__getattr__', '__setattr__',
-         '__delattr__']
-    return not name in dict.fromkeys(l)
-
-def wrap_type(protocol, tp, tp_id):
-    """ Wrap type to transpotable entity, taking
-    care about descriptors
-    """
-    dict_w = {}
-    for item in tp.__dict__.keys():
-        value = getattr(tp, item)
-        if not_ignore(item):
-            # we've got shortcut for method
-            if hasattr(value, '__get__') and not type(value) is MethodType:
-                if hasattr(value, '__set__'):
-                    dict_w[item] = ('get', item)
-                else:
-                    dict_w[item] = ('set', item)
-            else:
-                dict_w[item] = protocol.wrap(value)
-    bases_w = [protocol.wrap(i) for i in tp.__bases__ if i is not object]
-    return tp_id, tp.__name__, dict_w, bases_w
-
-def unwrap_descriptor_gen(desc_class):
-    def unwrapper(protocol, data):
-        name = data
-        obj = desc_class(protocol, name)
-        obj.__name__ = name
-        return obj
-    return unwrapper
-
-unwrap_get_descriptor = unwrap_descriptor_gen(GetDescriptor)
-unwrap_getset_descriptor = unwrap_descriptor_gen(GetSetDescriptor)
-
-def unwrap_type(objkeeper, protocol, type_id, name_, dict_w, bases_w):
-    """ Unwrap remote type, based on it's description
-    """
-    if bases_w == []:
-        bases = (object,)
-    else:
-        bases = tuple([protocol.unwrap(i) for i in bases_w])
-    d = dict.fromkeys(dict_w)
-    # XXX we do it in two steps to avoid cyclic dependencies,
-    #     probably there is some smarter way of doing this
-    if '__doc__' in dict_w:
-        d['__doc__'] = protocol.unwrap(dict_w['__doc__'])
-    tp = type(name_, bases, d)
-    objkeeper.register_remote_type(tp, type_id)
-    for key, value in dict_w.items():
-        if key != '__doc__':
-            v = protocol.unwrap(value)
-            if isinstance(v, FunctionType):
-                setattr(tp, key, staticmethod(v))
-            else:
-                setattr(tp, key, v)
diff --git a/lib_pypy/distributed/objkeeper.py b/lib_pypy/distributed/objkeeper.py
deleted file mode 100644
--- a/lib_pypy/distributed/objkeeper.py
+++ /dev/null
@@ -1,63 +0,0 @@
-
-""" objkeeper - Storage for remoteprotocol
-"""
-
-from types import FunctionType
-from distributed import faker
-
-class ObjKeeper(object):
-    def __init__(self, exported_names = {}):
-        self.exported_objects = [] # list of object that we've exported outside
-        self.exported_names = exported_names # dictionary of visible objects
-        self.exported_types = {} # dict of exported types
-        self.remote_types = {}
-        self.reverse_remote_types = {}
-        self.remote_objects = {}
-        self.exported_types_id = 0 # unique id of exported types
-        self.exported_types_reverse = {} # reverse dict of exported types
-    
-    def register_object(self, obj):
-        # XXX: At some point it makes sense not to export them again and again...
-        self.exported_objects.append(obj)
-        return len(self.exported_objects) - 1
-    
-    def ignore(self, key, value):
-        # there are some attributes, which cannot be modified later, nor
-        # passed into default values, ignore them
-        if key in ('__dict__', '__weakref__', '__class__',
-                   '__dict__', '__bases__'):
-            return True
-        return False
-    
-    def register_type(self, protocol, tp):
-        try:
-            return self.exported_types[tp]
-        except KeyError:
-            self.exported_types[tp] = self.exported_types_id
-            self.exported_types_reverse[self.exported_types_id] = tp
-            tp_id = self.exported_types_id
-            self.exported_types_id += 1
-
-        protocol.send(('type_reg', faker.wrap_type(protocol, tp, tp_id)))
-        return tp_id
-    
-    def fake_remote_type(self, protocol, tp_data):
-        type_id, name_, dict_w, bases_w = tp_data
-        tp = faker.unwrap_type(self, protocol, type_id, name_, dict_w, bases_w)
-
-    def register_remote_type(self, tp, type_id):
-        self.remote_types[type_id] = tp
-        self.reverse_remote_types[tp] = type_id
-    
-    def get_type(self, id):
-        return self.remote_types[id]
-
-    def get_object(self, id):
-        return self.exported_objects[id]
-    
-    def register_remote_object(self, controller, id):
-        self.remote_objects[controller] = id
-
-    def get_remote_object(self, controller):
-        return self.remote_objects[controller]
-        
diff --git a/lib_pypy/distributed/protocol.py b/lib_pypy/distributed/protocol.py
deleted file mode 100644
--- a/lib_pypy/distributed/protocol.py
+++ /dev/null
@@ -1,447 +0,0 @@
-
-""" Distributed controller(s) for use with transparent proxy objects
-
-First idea:
-
-1. We use py.execnet to create a connection to wherever
-2. We run some code there (RSync in advance makes some sense)
-3. We access remote objects like normal ones, with a special protocol
-
-Local side:
-  - Request an object from remote side from global namespace as simple
-    --- request(name) --->
-  - Receive an object which is in protocol described below which is
-    constructed as shallow copy of the remote type.
-
-    Shallow copy is defined as follows:
-
-    - for interp-level object that we know we can provide transparent proxy
-      we just do that
-
-    - for others we fake or fail depending on object
-
-    - for user objects, we create a class which fakes all attributes of
-      a class as transparent proxies of remote objects, we create an instance
-      of that class and populate __dict__
-
-    - for immutable types, we just copy that
-
-Remote side:
-  - we run code, whatever we like
-  - additionally, we've got thread exporting stuff (or just exporting
-    globals, whatever)
-  - for every object, we just send an object, or provide a protocol for
-    sending it in a different way.
-
-"""
-
-try:
-    from __pypy__ import tproxy as proxy
-    from __pypy__ import get_tproxy_controller
-except ImportError:
-    raise ImportError("Cannot work without transparent proxy functionality")
-
-from distributed.objkeeper import ObjKeeper
-from distributed import faker
-import sys
-
-class ObjectNotFound(Exception):
-    pass
-
-# XXX We do not make any garbage collection. We'll need it at some point
-
-"""
-TODO list:
-
-1. Garbage collection - we would like probably to use weakrefs, but
-   since they're not perfectly working in pypy, let's leave it alone for now
-2. Some error handling - exceptions are working, there are still some
-   applications where it all explodes.
-3. Support inheritance and recursive types
-"""
-
-from __pypy__ import internal_repr
-
-import types
-from marshal import dumps
-import exceptions
-
-# just placeholders for letter_types value
-class RemoteBase(object):
-    pass
-
-class DataDescriptor(object):
-    pass
-
-class NonDataDescriptor(object):
-    pass
-# end of placeholders
-
-class AbstractProtocol(object):
-    immutable_primitives = (str, int, float, long, unicode, bool, types.NotImplementedType)
-    mutable_primitives = (list, dict, types.FunctionType, types.FrameType, types.TracebackType,
-        types.CodeType)
-    exc_dir = dict((val, name) for name, val in exceptions.__dict__.iteritems())
-    
-    letter_types = {
-        'l' : list,
-        'd' : dict,
-        'c' : types.CodeType,
-        't' : tuple,
-        'e' : Exception,
-        'ex': exceptions, # for instances
-        'i' : int,
-        'b' : bool,
-        'f' : float,
-        'u' : unicode,
-        'l' : long,
-        's' : str,
-        'ni' : types.NotImplementedType,
-        'n' : types.NoneType,
-        'lst' : list,
-        'fun' : types.FunctionType,
-        'cus' : object,
-        'meth' : types.MethodType,
-        'type' : type,
-        'tp' : None,
-        'fr' : types.FrameType,
-        'tb' : types.TracebackType,
-        'reg' : RemoteBase,
-        'get' : NonDataDescriptor,
-        'set' : DataDescriptor,
-    }
-    type_letters = dict([(value, key) for key, value in letter_types.items()])
-    assert len(type_letters) == len(letter_types)
-    
-    def __init__(self, exported_names={}):
-        self.keeper = ObjKeeper(exported_names)
-        #self.remote_objects = {} # a dictionary controller --> id
-        #self.objs = [] # we just store everything, maybe later
-        #   # we'll need some kind of garbage collection
-
-    def wrap(self, obj):
-        """ Wrap an object as sth prepared for sending
-        """
-        def is_element(x, iterable):
-            try:
-                return x in iterable
-            except (TypeError, ValueError):
-                return False
-        
-        tp = type(obj)
-        ctrl = get_tproxy_controller(obj)
-        if ctrl:
-            return "tp", self.keeper.get_remote_object(ctrl)
-        elif obj is None:
-            return self.type_letters[tp]
-        elif tp in self.immutable_primitives:
-            # simple, immutable object, just copy
-            return (self.type_letters[tp], obj)
-        elif hasattr(obj, '__class__') and obj.__class__ in self.exc_dir:
-            return (self.type_letters[Exception], (self.exc_dir[obj.__class__], \
-                self.wrap(obj.args)))
-        elif is_element(obj, self.exc_dir): # weird hashing problems
-            return (self.type_letters[exceptions], self.exc_dir[obj])
-        elif tp is tuple:
-            # we just pack all of the items
-            return ('t', tuple([self.wrap(elem) for elem in obj]))
-        elif tp in self.mutable_primitives:
-            id = self.keeper.register_object(obj)
-            return (self.type_letters[tp], id)
-        elif tp is type:
-            try:
-                return "reg", self.keeper.reverse_remote_types[obj]
-            except KeyError:
-                pass
-            try:
-                return self.type_letters[tp], self.type_letters[obj]
-            except KeyError:
-                id = self.register_type(obj)
-                return (self.type_letters[tp], id)
-        elif tp is types.MethodType:
-            w_class = self.wrap(obj.im_class)
-            w_func = self.wrap(obj.im_func)
-            w_self = self.wrap(obj.im_self)
-            return (self.type_letters[tp], (w_class, \
-                self.wrap(obj.im_func.func_name), w_func, w_self))
-        else:
-            id = self.keeper.register_object(obj)
-            w_tp = self.wrap(tp)
-            return ("cus", (w_tp, id))
-    
-    def unwrap(self, data):
-        """ Unwrap an object
-        """
-        if data == 'n':
-            return None
-        tp_letter, obj_data = data
-        tp = self.letter_types[tp_letter]
-        if tp is None:
-            return self.keeper.get_object(obj_data)
-        elif tp is RemoteBase:
-            return self.keeper.exported_types_reverse[obj_data]
-        elif tp in self.immutable_primitives:
-            return obj_data # this is the object
-        elif tp is tuple:
-            return tuple([self.unwrap(i) for i in obj_data])
-        elif tp in self.mutable_primitives:
-            id = obj_data
-            ro = RemoteBuiltinObject(self, id)
-            self.keeper.register_remote_object(ro.perform, id)
-            p = proxy(tp, ro.perform)
-            ro.obj = p
-            return p
-        elif tp is Exception:
-            cls_name, w_args = obj_data
-            return getattr(exceptions, cls_name)(self.unwrap(w_args))
-        elif tp is exceptions:
-            cls_name = obj_data
-            return getattr(exceptions, cls_name)
-        elif tp is types.MethodType:
-            w_class, w_name, w_func, w_self = obj_data
-            tp = self.unwrap(w_class)
-            name = self.unwrap(w_name)
-            self_ = self.unwrap(w_self)
-            if self_ is not None:
-                if tp is None:
-                    setattr(self_, name, classmethod(self.unwrap(w_func)))
-                    return getattr(self_, name)
-                return getattr(tp, name).__get__(self_, tp)
-            func = self.unwrap(w_func)
-            setattr(tp, name, func)
-            return getattr(tp, name)
-        elif tp is type:
-            if isinstance(obj_data, str):
-                return self.letter_types[obj_data]
-            id = obj_data
-            return self.get_type(obj_data)
-        elif tp is DataDescriptor:            
-            return faker.unwrap_getset_descriptor(self, obj_data)
-        elif tp is NonDataDescriptor:
-            return faker.unwrap_get_descriptor(self, obj_data)
-        elif tp is object:
-            # we need to create a proper type
-            w_tp, id = obj_data
-            real_tp = self.unwrap(w_tp)
-            ro = RemoteObject(self, id)
-            self.keeper.register_remote_object(ro.perform, id)
-            p = proxy(real_tp, ro.perform)
-            ro.obj = p
-            return p
-        else:
-            raise NotImplementedError("Cannot unwrap %s" % (data,))
-    
-    def perform(self, *args, **kwargs):
-        raise NotImplementedError("Abstract only protocol")
-    
-    # some simple wrappers
-    def pack_args(self, args, kwargs):
-        return self.pack_list(args), self.pack_dict(kwargs)
-    
-    def pack_list(self, lst):
-        return [self.wrap(i) for i in lst]
-    
-    def pack_dict(self, d):
-        return dict([(self.wrap(key), self.wrap(val)) for key, val in d.items()])
-    
-    def unpack_args(self, args, kwargs):
-        return self.unpack_list(args), self.unpack_dict(kwargs)
-    
-    def unpack_list(self, lst):
-        return [self.unwrap(i) for i in lst]
-    
-    def unpack_dict(self, d):
-        return dict([(self.unwrap(key), self.unwrap(val)) for key, val in d.items()])
-    
-    def register_type(self, tp):
-        return self.keeper.register_type(self, tp)
-    
-    def get_type(self, id):
-        return self.keeper.get_type(id)
-    
-class LocalProtocol(AbstractProtocol):
-    """ This is stupid protocol for testing purposes only
-    """
-    def __init__(self):
-        super(LocalProtocol, self).__init__()
-        self.types = []
-   
-    def perform(self, id, name, *args, **kwargs):
-        obj = self.keeper.get_object(id)
-        # we pack and than unpack, for tests
-        args, kwargs = self.pack_args(args, kwargs)
-        assert isinstance(name, str)
-        dumps((args, kwargs))
-        args, kwargs = self.unpack_args(args, kwargs)
-        return getattr(obj, name)(*args, **kwargs)
-    
-    def register_type(self, tp):
-        self.types.append(tp)
-        return len(self.types) - 1
-    
-    def get_type(self, id):
-        return self.types[id]
-
-def remote_loop(protocol):
-    # the simplest version possible, without any concurrency and such
-    wrap = protocol.wrap
-    unwrap = protocol.unwrap
-    send = protocol.send
-    receive = protocol.receive
-    # we need this for wrap/unwrap
-    while 1:
-        command, data = receive()
-        if command == 'get':
-            try:
-                item = protocol.keeper.exported_names[data]
-            except KeyError:
-                send(("finished_error",data))
-            else:
-                # XXX wrapping problems catching? do we have any?
-                send(("finished", wrap(item)))
-        elif command == 'call':
-            id, name, args, kwargs = data
-            args, kwargs = protocol.unpack_args(args, kwargs)
-            try:
-                retval = getattr(protocol.keeper.get_object(id), name)(*args, **kwargs)
-            except:
-                send(("raised", wrap(sys.exc_info())))
-            else:
-                send(("finished", wrap(retval)))
-        elif command == 'finished':
-            return unwrap(data)
-        elif command == 'finished_error':
-            raise ObjectNotFound("Cannot find name %s" % (data,))
-        elif command == 'raised':
-            exc, val, tb = unwrap(data)
-            raise exc, val, tb
-        elif command == 'type_reg':
-            protocol.keeper.fake_remote_type(protocol, data)
-        elif command == 'force':
-            obj = protocol.keeper.get_object(data)
-            w_obj = protocol.pack(obj)
-            send(("forced", w_obj))
-        elif command == 'forced':
-            obj = protocol.unpack(data)
-            return obj
-        elif command == 'desc_get':
-            name, w_obj, w_type = data
-            obj = protocol.unwrap(w_obj)
-            type_ = protocol.unwrap(w_type)
-            if obj:
-                type__ = type(obj)
-            else:
-                type__ = type_
-            send(('finished', protocol.wrap(getattr(type__, name).__get__(obj, type_))))
-
-        elif command == 'desc_set':
-            name, w_obj, w_value = data
-            obj = protocol.unwrap(w_obj)
-            value = protocol.unwrap(w_value)
-            getattr(type(obj), name).__set__(obj, value)
-            send(('finished', protocol.wrap(None)))
-        elif command == 'remote_keys':
-            keys = protocol.keeper.exported_names.keys()
-            send(('finished', protocol.wrap(keys)))
-        else:
-            raise NotImplementedError("command %s" % command)
-
-class RemoteProtocol(AbstractProtocol):
-    #def __init__(self, gateway, remote_code):
-    #    self.gateway = gateway
-    def __init__(self, send, receive, exported_names={}):
-        super(RemoteProtocol, self).__init__(exported_names)
-        #self.exported_names = exported_names
-        self.send = send
-        self.receive = receive
-        #self.type_cache = {}
-        #self.type_id = 0
-        #self.remote_types = {}
-    
-    def perform(self, id, name, *args, **kwargs):
-        args, kwargs = self.pack_args(args, kwargs)
-        self.send(('call', (id, name, args, kwargs)))
-        try:
-            retval = remote_loop(self)
-        except:
-            e, val, tb = sys.exc_info()
-            raise e, val, tb.tb_next.tb_next
-        return retval
-    
-    def get_remote(self, name):
-        self.send(("get", name))
-        retval = remote_loop(self)
-        return retval
-    
-    def force(self, id):
-        self.send(("force", id))
-        retval = remote_loop(self)
-        return retval
-    
-    def pack(self, obj):
-        if isinstance(obj, list):
-            return "l", self.pack_list(obj)
-        elif isinstance(obj, dict):
-            return "d", self.pack_dict(obj)
-        else:
-            raise NotImplementedError("Cannot pack %s" % obj)
-        
-    def unpack(self, data):
-        letter, w_obj = data
-        if letter == 'l':
-            return self.unpack_list(w_obj)
-        elif letter == 'd':
-            return self.unpack_dict(w_obj)
-        else:
-            raise NotImplementedError("Cannot unpack %s" % (data,))
-
-    def get(self, name, obj, type):
-        self.send(("desc_get", (name, self.wrap(obj), self.wrap(type))))
-        return remote_loop(self)
-
-    def set(self, obj, value):
-        self.send(("desc_set", (name, self.wrap(obj), self.wrap(value))))
-
-    def remote_keys(self):
-        self.send(("remote_keys",None))
-        return remote_loop(self)
-
-class RemoteObject(object):
-    def __init__(self, protocol, id):
-        self.id = id
-        self.protocol = protocol
-    
-    def perform(self, name, *args, **kwargs):
-        return self.protocol.perform(self.id, name, *args, **kwargs)
-
-class RemoteBuiltinObject(RemoteObject):
-    def __init__(self, protocol, id):
-        self.id = id
-        self.protocol = protocol
-        self.forced = False
-    
-    def perform(self, name, *args, **kwargs):
-        # XXX: Check who really goes here
-        if self.forced:
-            return getattr(self.obj, name)(*args, **kwargs)
-        if name in ('__eq__', '__ne__', '__lt__', '__gt__', '__ge__', '__le__',
-            '__cmp__'):
-            self.obj = self.protocol.force(self.id)
-            return getattr(self.obj, name)(*args, **kwargs)
-        return self.protocol.perform(self.id, name, *args, **kwargs)
-
-def test_env(exported_names):
-    from stackless import channel, tasklet, run
-    inp, out = channel(), channel()
-    remote_protocol = RemoteProtocol(inp.send, out.receive, exported_names)
-    t = tasklet(remote_loop)(remote_protocol)
-    
-    #def send_trace(data):
-    #    print "Sending %s" % (data,)
-    #    out.send(data)
-
-    #def receive_trace():
-    #    data = inp.receive()
-    #    print "Received %s" % (data,)
-    #    return data
-    return RemoteProtocol(out.send, inp.receive)
diff --git a/lib_pypy/distributed/socklayer.py b/lib_pypy/distributed/socklayer.py
deleted file mode 100644
--- a/lib_pypy/distributed/socklayer.py
+++ /dev/null
@@ -1,83 +0,0 @@
-
-import py
-from socket import socket
-
-raise ImportError("XXX needs import adaptation as 'green' is removed from py lib for years")
-from py.impl.green.msgstruct import decodemessage, message
-from socket import socket, AF_INET, SOCK_STREAM
-import marshal
-import sys
-
-TRACE = False
-def trace(msg):
-    if TRACE:
-        print >>sys.stderr, msg
-
-class Finished(Exception):
-    pass
-
-class SocketWrapper(object):
-    def __init__(self, conn):
-        self.buffer = ""
-        self.conn = conn
-
-class ReceiverWrapper(SocketWrapper):
-    def receive(self):
-        msg, self.buffer = decodemessage(self.buffer)
-        while msg is None:
-            data = self.conn.recv(8192)
-            if not data:
-                raise Finished()
-            self.buffer += data
-            msg, self.buffer = decodemessage(self.buffer)
-        assert msg[0] == 'c'
-        trace("received %s" % msg[1])
-        return marshal.loads(msg[1])
-
-class SenderWrapper(SocketWrapper):
-    def send(self, data):
-        trace("sending %s" % (data,))
-        self.conn.sendall(message('c', marshal.dumps(data)))
-        trace("done")
-
-def socket_listener(address, socket=socket):
-    s = socket(AF_INET, SOCK_STREAM)
-    s.bind(address)
-    s.listen(1)
-    print "Waiting for connection on %s" % (address,)
-    conn, addr = s.accept()
-    print "Connected from %s" % (addr,)
-
-    return SenderWrapper(conn).send, ReceiverWrapper(conn).receive
-
-def socket_loop(address, to_export, socket=socket):
-    from distributed import RemoteProtocol, remote_loop
-    try:
-        send, receive = socket_listener(address, socket)
-        remote_loop(RemoteProtocol(send, receive, to_export))
-    except Finished:
-        pass
-
-def socket_connecter(address, socket=socket):
-    s = socket(AF_INET, SOCK_STREAM)
-    print "Connecting %s" % (address,)
-    s.connect(address)
-    
-    return SenderWrapper(s).send, ReceiverWrapper(s).receive
-
-def connect(address, socket=socket):
-    from distributed.support import RemoteView
-    from distributed import RemoteProtocol
-    return RemoteView(RemoteProtocol(*socket_connecter(address, socket)))
-
-def spawn_remote_side(code, gw):
-    """ A very simple wrapper around greenexecnet to allow
-    spawning a remote side of lib/distributed
-    """
-    from distributed import RemoteProtocol
-    extra = str(py.code.Source("""
-    from distributed import remote_loop, RemoteProtocol
-    remote_loop(RemoteProtocol(channel.send, channel.receive, globals()))
-    """))
-    channel = gw.remote_exec(code + "\n" + extra)
-    return RemoteProtocol(channel.send, channel.receive)
diff --git a/lib_pypy/distributed/support.py b/lib_pypy/distributed/support.py
deleted file mode 100644
--- a/lib_pypy/distributed/support.py
+++ /dev/null
@@ -1,17 +0,0 @@
-
-""" Some random support functions
-"""
-
-from distributed.protocol import ObjectNotFound
-
-class RemoteView(object):
-    def __init__(self, protocol):
-        self.__dict__['__protocol'] = protocol
-
-    def __getattr__(self, name):
-        if name == '__dict__':
-            return super(RemoteView, self).__getattr__(name)
-        try:
-            return self.__dict__['__protocol'].get_remote(name)
-        except ObjectNotFound:
-            raise AttributeError(name)
diff --git a/lib_pypy/distributed/test/__init__.py b/lib_pypy/distributed/test/__init__.py
deleted file mode 100644
diff --git a/lib_pypy/distributed/test/test_distributed.py b/lib_pypy/distributed/test/test_distributed.py
deleted file mode 100644
--- a/lib_pypy/distributed/test/test_distributed.py
+++ /dev/null
@@ -1,301 +0,0 @@
-
-""" Controllers tests
-"""
-
-from pypy.conftest import gettestobjspace
-import sys
-import pytest
-
-class AppTestDistributed(object):
-    def setup_class(cls):
-        cls.space = gettestobjspace(**{"objspace.std.withtproxy": True,
-            "usemodules":("_continuation",)})
-
-    def test_init(self):
-        import distributed
-
-    def test_protocol(self):
-        from distributed.protocol import AbstractProtocol
-        protocol = AbstractProtocol()
-        for item in ("aaa", 3, u"aa", 344444444444444444L, 1.2, (1, "aa")):
-            assert protocol.unwrap(protocol.wrap(item)) == item
-        assert type(protocol.unwrap(protocol.wrap([1,2,3]))) is list
-        assert type(protocol.unwrap(protocol.wrap({"a":3}))) is dict
-        
-        def f():
-            pass
-        
-        assert type(protocol.unwrap(protocol.wrap(f))) is type(f)
-
-    def test_method_of_false_obj(self):
-        from distributed.protocol import AbstractProtocol
-        protocol = AbstractProtocol()
-        lst = []
-        m = lst.append
-        assert type(protocol.unwrap(protocol.wrap(m))) is type(m)
-
-    def test_protocol_run(self):
-        l = [1,2,3]
-        from distributed.protocol import LocalProtocol
-        protocol = LocalProtocol()
-        wrap = protocol.wrap
-        unwrap = protocol.unwrap
-        item = unwrap(wrap(l))
-        assert len(item) == 3
-        assert item[2] == 3
-        item += [1,1,1]
-        assert len(item) == 6
-
-    def test_protocol_call(self):
-        def f(x, y):
-            return x + y
-        
-        from distributed.protocol import LocalProtocol
-        protocol = LocalProtocol()
-        wrap = protocol.wrap
-        unwrap = protocol.unwrap
-        item = unwrap(wrap(f))
-        assert item(3, 2) == 5
-
-    def test_simulation_call(self):
-        def f(x, y):
-            return x + y
-        
-        import types
-        from distributed import RemoteProtocol
-        import sys
-
-        data = []
-        result = []
-        protocol = RemoteProtocol(result.append, data.pop)
-        data += [("finished", protocol.wrap(5)), ("finished", protocol.wrap(f))]
-        fun = protocol.get_remote("f")
-        assert isinstance(fun, types.FunctionType)
-        assert fun(2, 3) == 5
-
-    def test_local_obj(self):
-        class A(object):
-            def __init__(self, x):
-                self.x = x
-            
-            def __len__(self):
-                return self.x + 8
-        
-        from distributed.protocol import LocalProtocol
-        protocol = LocalProtocol()
-        wrap = protocol.wrap
-        unwrap = protocol.unwrap
-        item = unwrap(wrap(A(3)))
-        assert item.x == 3
-        assert len(item) == 11
-
-class AppTestDistributedTasklets(object):
-    spaceconfig = {"objspace.std.withtproxy": True,
-                   "objspace.usemodules._continuation": True}
-    def setup_class(cls):
-        cls.w_test_env = cls.space.appexec([], """():
-        from distributed import test_env
-        return test_env
-        """)
-        cls.reclimit = sys.getrecursionlimit()
-        sys.setrecursionlimit(100000)
-
-    def teardown_class(cls):
-        sys.setrecursionlimit(cls.reclimit)
-    
-    def test_remote_protocol_call(self):
-        def f(x, y):
-            return x + y
-        
-        protocol = self.test_env({"f": f})
-        fun = protocol.get_remote("f")
-        assert fun(2, 3) == 5
-
-    def test_callback(self):
-        def g():
-            return 8
-        
-        def f(x):
-            return x + g()
-        
-        protocol = self.test_env({"f":f})
-        fun = protocol.get_remote("f")
-        assert fun(8) == 16
-    
-    def test_remote_dict(self):
-        #skip("Land of infinite recursion")
-        d = {'a':3}
-        protocol = self.test_env({'d':d})
-        xd = protocol.get_remote('d')
-        #assert d['a'] == xd['a']
-        assert d.keys() == xd.keys()
-        assert d.values() == xd.values()
-        assert d == xd
-        
-    def test_remote_obj(self):
-        class A(object):
-            def __init__(self, x):
-                self.x = x
-            
-            def __len__(self):
-                return self.x + 8
-        a = A(3)
-        
-        protocol = self.test_env({'a':a})
-        xa = protocol.get_remote("a")
-        assert xa.x == 3
-        assert len(xa) == 11
-    
-    def test_remote_doc_and_callback(self):
-        class A(object):
-            """xxx"""
-            def __init__(self):
-                pass
-
-            def meth(self, x):
-                return x() + 3
-        
-        def x():
-            return 1
-        
-        a = A()
-        
-        protocol = self.test_env({'a':a})
-        xa = protocol.get_remote('a')
-        assert xa.__class__.__doc__ == 'xxx'
-        assert xa.meth(x) == 4
-
-    def test_double_reference(self):
-        class A(object):
-            def meth(self, one):
-                self.one = one
-            
-            def perform(self):
-                return 1 + len(self.one())
-        
-        class B(object):
-            def __call__(self):
-                return [1,2,3]
-        
-        a = A()
-        protocol = self.test_env({'a': a})
-        xa = protocol.get_remote('a')
-        xa.meth(B())
-        assert xa.perform() == 4
-
-    def test_frame(self):
-        #skip("Land of infinite recursion")
-        import sys
-        f = sys._getframe()
-        protocol = self.test_env({'f':f})
-        xf = protocol.get_remote('f')
-        assert f.f_globals.keys() == xf.f_globals.keys()
-        assert f.f_locals.keys() == xf.f_locals.keys()
-
-    def test_remote_exception(self):
-        def raising():
-            1/0
-        
-        protocol = self.test_env({'raising':raising})
-        xr = protocol.get_remote('raising')
-        try:
-            xr()
-        except ZeroDivisionError:
-            import sys
-            exc_info, val, tb  = sys.exc_info()
-            #assert tb.tb_next is None
-        else:
-            raise AssertionError("Did not raise")
-
-    def test_remote_classmethod(self):
-        class A(object):
-            z = 8
-
-            @classmethod
-            def x(cls):
-                return cls.z
-
-        a = A()
-        protocol = self.test_env({'a':a})
-        xa = protocol.get_remote("a")
-        res = xa.x()
-        assert res == 8
-
-    def test_types_reverse_mapping(self):
-        class A(object):
-            def m(self, tp):
-                assert type(self) is tp
-
-        a = A()
-        protocol = self.test_env({'a':a, 'A':A})
-        xa = protocol.get_remote('a')
-        xA = protocol.get_remote('A')
-        xa.m(xA)
-
-    def test_instantiate_remote_type(self):
-        class C(object):
-            def __init__(self, y):
-                self.y = y
-            
-            def x(self):
-                return self.y
-
-        protocol = self.test_env({'C':C})
-        xC = protocol.get_remote('C')
-        xc = xC(3)
-        res = xc.x()
-        assert res == 3
-
-    def test_remote_sys(self):
-        import sys
-
-        protocol = self.test_env({'sys':sys})
-        s = protocol.get_remote('sys')
-        l = dir(s)
-        assert l
-
-    def test_remote_file_access(self):
-        skip("Descriptor logic seems broken")
-        protocol = self.test_env({'f':open})
-        xf = protocol.get_remote('f')
-        data = xf('/etc/passwd').read()
-        assert data
-
-    def test_real_descriptor(self):
-        class getdesc(object):
-            def __get__(self, obj, val=None):
-                if obj is not None:
-                    assert type(obj) is X
-                return 3
-
-        class X(object):
-            x = getdesc()
-
-        x = X()
-
-        protocol = self.test_env({'x':x})
-        xx = protocol.get_remote('x')
-        assert xx.x == 3
-    
-    def test_bases(self):
-        class X(object):
-            pass
-
-        class Y(X):
-            pass
-
-        y = Y()
-        protocol = self.test_env({'y':y, 'X':X})
-        xy = protocol.get_remote('y')
-        xX = protocol.get_remote('X')
-        assert isinstance(xy, xX)
-
-    def test_key_error(self):
-        from distributed import ObjectNotFound
-        protocol = self.test_env({})
-        raises(ObjectNotFound, "protocol.get_remote('x')")
-
-    def test_list_items(self):
-        protocol = self.test_env({'x':3, 'y':8})
-        assert sorted(protocol.remote_keys()) == ['x', 'y']
-
diff --git a/lib_pypy/distributed/test/test_greensock.py b/lib_pypy/distributed/test/test_greensock.py
deleted file mode 100644
--- a/lib_pypy/distributed/test/test_greensock.py
+++ /dev/null
@@ -1,62 +0,0 @@
-
-import py
-from pypy.conftest import gettestobjspace, option
-
-def setup_module(mod):
-    py.test.importorskip("pygreen")   # found e.g. in py/trunk/contrib 
-
-class AppTestDistributedGreensock(object):
-    def setup_class(cls):
-        if not option.runappdirect:
-            py.test.skip("Cannot run this on top of py.py because of PopenGateway")
-        cls.space = gettestobjspace(**{"objspace.std.withtproxy": True,
-                                       "usemodules":("_continuation",)})
-        cls.w_remote_side_code = cls.space.appexec([], """():
-        import sys
-        sys.path.insert(0, '%s')
-        remote_side_code = '''
-class A:
-   def __init__(self, x):
-       self.x = x
-            
-   def __len__(self):
-       return self.x + 8
-
-   def raising(self):
-       1/0
-
-   def method(self, x):
-       return x() + self.x
-
-a = A(3)
-
-def count():
-    x = 10
-    # naive counting :)
-    result = 1
-    for i in range(x):
-        result += 1
-    return result
-'''
-        return remote_side_code
-        """ % str(py.path.local(__file__).dirpath().dirpath().dirpath().dirpath()))
-
-    def test_remote_call(self):
-        from distributed import socklayer
-        import sys
-        from pygreen.greenexecnet import PopenGateway
-        gw = PopenGateway()
-        rp = socklayer.spawn_remote_side(self.remote_side_code, gw)
-        a = rp.get_remote("a")
-        assert a.method(lambda : 13) == 16
-    
-    def test_remote_counting(self):
-        from distributed import socklayer
-        from pygreen.greensock2 import allof
-        from pygreen.greenexecnet import PopenGateway
-        gws = [PopenGateway() for i in range(3)]
-        rps = [socklayer.spawn_remote_side(self.remote_side_code, gw)
-               for gw in gws]
-        counters = [rp.get_remote("count") for rp in rps]
-        assert allof(*counters) == (11, 11, 11)
-
diff --git a/lib_pypy/distributed/test/test_socklayer.py b/lib_pypy/distributed/test/test_socklayer.py
deleted file mode 100644
--- a/lib_pypy/distributed/test/test_socklayer.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import py
-from pypy.conftest import gettestobjspace
-
-def setup_module(mod):
-    py.test.importorskip("pygreen")   # found e.g. in py/trunk/contrib 
-
-# XXX think how to close the socket
-
-class AppTestSocklayer:
-    def setup_class(cls):
-        cls.space = gettestobjspace(**{"objspace.std.withtproxy": True,
-                                       "usemodules":("_continuation",
-                                                     "_socket", "select")})
-    
-    def test_socklayer(self):
-        class X(object):
-            z = 3
-
-        x = X()
-
-        try:
-            import py
-        except ImportError:
-            skip("pylib not importable")
-        from pygreen.pipe.gsocke import GreenSocket
-        from distributed.socklayer import socket_loop, connect
-        from pygreen.greensock2 import oneof, allof
-
-        def one():
-            socket_loop(('127.0.0.1', 21211), {'x':x}, socket=GreenSocket)
-
-        def two():
-            rp = connect(('127.0.0.1', 21211), GreenSocket)
-            assert rp.x.z == 3
-
-        oneof(one, two)
diff --git a/lib_pypy/pyrepl/readline.py b/lib_pypy/pyrepl/readline.py
--- a/lib_pypy/pyrepl/readline.py
+++ b/lib_pypy/pyrepl/readline.py
@@ -194,7 +194,7 @@
         except _error:
             return _old_raw_input(prompt)
         reader.ps1 = prompt
-        return reader.readline(reader, startup_hook=self.startup_hook)
+        return reader.readline(startup_hook=self.startup_hook)
 
     def multiline_input(self, more_lines, ps1, ps2, returns_unicode=False):
         """Read an input on possibly multiple lines, asking for more
diff --git a/lib_pypy/sip.py b/lib_pypy/sip.py
deleted file mode 100644
--- a/lib_pypy/sip.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from _rpyc_support import proxy_module
-
-proxy_module(globals())
-del proxy_module
diff --git a/pypy/annotation/annrpython.py b/pypy/annotation/annrpython.py
--- a/pypy/annotation/annrpython.py
+++ b/pypy/annotation/annrpython.py
@@ -133,44 +133,6 @@
         self.build_graph_types(graph, inputcells, complete_now=False)
         self.complete_helpers(policy)
         return graph
-    
-    def annotate_helper_method(self, _class, attr, args_s, policy=None):
-        """ Warning! this method is meant to be used between
-        annotation and rtyping
-        """
-        if policy is None:
-            from pypy.annotation.policy import AnnotatorPolicy
-            policy = AnnotatorPolicy()
-        
-        assert attr != '__class__'
-        classdef = self.bookkeeper.getuniqueclassdef(_class)
-        attrdef = classdef.find_attribute(attr)
-        s_result = attrdef.getvalue()
-        classdef.add_source_for_attribute(attr, classdef.classdesc)
-        self.bookkeeper
-        assert isinstance(s_result, annmodel.SomePBC)
-        olddesc = s_result.any_description()
-        desc = olddesc.bind_self(classdef)
-        args = self.bookkeeper.build_args("simple_call", args_s[:])
-        desc.consider_call_site(self.bookkeeper, desc.getcallfamily(), [desc],
-            args, annmodel.s_ImpossibleValue, None)
-        result = []
-        def schedule(graph, inputcells):
-            result.append((graph, inputcells))
-            return annmodel.s_ImpossibleValue
-
-        prevpolicy = self.policy
-        self.policy = policy
-        self.bookkeeper.enter(None)
-        try:
-            desc.pycall(schedule, args, annmodel.s_ImpossibleValue)
-        finally:
-            self.bookkeeper.leave()
-            self.policy = prevpolicy
-        [(graph, inputcells)] = result
-        self.build_graph_types(graph, inputcells, complete_now=False)
-        self.complete_helpers(policy)
-        return graph
 
     def complete_helpers(self, policy):
         saved = self.policy, self.added_blocks
diff --git a/pypy/annotation/binaryop.py b/pypy/annotation/binaryop.py
--- a/pypy/annotation/binaryop.py
+++ b/pypy/annotation/binaryop.py
@@ -7,7 +7,7 @@
 from pypy.tool.pairtype import pair, pairtype
 from pypy.annotation.model import SomeObject, SomeInteger, SomeBool, s_Bool
 from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict
-from pypy.annotation.model import SomeUnicodeCodePoint
+from pypy.annotation.model import SomeUnicodeCodePoint, SomeStringOrUnicode
 from pypy.annotation.model import SomeTuple, SomeImpossibleValue, s_ImpossibleValue
 from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeIterator
 from pypy.annotation.model import SomePBC, SomeFloat, s_None
@@ -470,30 +470,37 @@
             "string formatting mixing strings and unicode not supported")
 
 
-class __extend__(pairtype(SomeString, SomeTuple)):
-    def mod((str, s_tuple)):
+class __extend__(pairtype(SomeString, SomeTuple),
+                 pairtype(SomeUnicodeString, SomeTuple)):
+    def mod((s_string, s_tuple)):
+        is_string = isinstance(s_string, SomeString)
+        is_unicode = isinstance(s_string, SomeUnicodeString)
+        assert is_string or is_unicode
         for s_item in s_tuple.items:
-            if isinstance(s_item, (SomeUnicodeCodePoint, SomeUnicodeString)):
+            if (is_unicode and isinstance(s_item, (SomeChar, SomeString)) or
+                is_string and isinstance(s_item, (SomeUnicodeCodePoint,
+                                                  SomeUnicodeString))):
                 raise NotImplementedError(
                     "string formatting mixing strings and unicode not supported")
-        getbookkeeper().count('strformat', str, s_tuple)
-        no_nul = str.no_nul
+        getbookkeeper().count('strformat', s_string, s_tuple)
+        no_nul = s_string.no_nul
         for s_item in s_tuple.items:
             if isinstance(s_item, SomeFloat):
                 pass   # or s_item is a subclass, like SomeInteger
-            elif isinstance(s_item, SomeString) and s_item.no_nul:
+            elif isinstance(s_item, SomeStringOrUnicode) and s_item.no_nul:
                 pass
             else:
                 no_nul = False
                 break
-        return SomeString(no_nul=no_nul)
+        return s_string.__class__(no_nul=no_nul)
 
 
-class __extend__(pairtype(SomeString, SomeObject)):
+class __extend__(pairtype(SomeString, SomeObject),
+                 pairtype(SomeUnicodeString, SomeObject)):
 
-    def mod((str, args)):
-        getbookkeeper().count('strformat', str, args)
-        return SomeString()
+    def mod((s_string, args)):
+        getbookkeeper().count('strformat', s_string, args)
+        return s_string.__class__()
 
 class __extend__(pairtype(SomeFloat, SomeFloat)):
     
@@ -659,7 +666,7 @@
 
     def mul((str1, int2)): # xxx do we want to support this
         getbookkeeper().count("str_mul", str1, int2)
-        return SomeString()
+        return SomeString(no_nul=str1.no_nul)
 
 class __extend__(pairtype(SomeUnicodeString, SomeInteger)):
     def getitem((str1, int2)):
diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py
--- a/pypy/annotation/bookkeeper.py
+++ b/pypy/annotation/bookkeeper.py
@@ -201,6 +201,7 @@
                     for op in block.operations:
                         if op.opname in ('simple_call', 'call_args'):
                             yield op
+
                         # some blocks are partially annotated
                         if binding(op.result, None) is None:
                             break   # ignore the unannotated part
diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -514,9 +514,9 @@
                     continue
                 self.add_source_attribute(name, value, mixin=True)
 
-    def add_sources_for_class(self, cls, mixin=False):
+    def add_sources_for_class(self, cls):
         for name, value in cls.__dict__.items():
-            self.add_source_attribute(name, value, mixin)
+            self.add_source_attribute(name, value)
 
     def getallclassdefs(self):
         return self._classdefs.values()
diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py
--- a/pypy/annotation/test/test_annrpython.py
+++ b/pypy/annotation/test/test_annrpython.py
@@ -2138,6 +2138,15 @@
         assert isinstance(s, annmodel.SomeString)
         assert s.no_nul
 
+    def test_mul_str0(self):
+        def f(s):
+            return s*10
+        a = self.RPythonAnnotator()
+        s = a.build_types(f, [annmodel.SomeString(no_nul=True)])
+        assert isinstance(s, annmodel.SomeString)
+        assert s.no_nul
+        
+
     def test_non_none_and_none_with_isinstance(self):
         class A(object):
             pass
@@ -2738,20 +2747,6 @@
         s = a.build_types(f, [])
         assert s.knowntype == int
 
-    def test_helper_method_annotator(self):
-        def fun():
-            return 21
-
-        class A(object):
-            def helper(self):
-                return 42
-
-        a = self.RPythonAnnotator()
-        a.build_types(fun, [])
-        a.annotate_helper_method(A, "helper", [])
-        assert a.bookkeeper.getdesc(A.helper).getuniquegraph()
-        assert a.bookkeeper.getdesc(A().helper).getuniquegraph()
-
     def test_chr_out_of_bounds(self):
         def g(n, max):
             if n < max:
@@ -3394,6 +3389,22 @@
         s = a.build_types(f, [str])
         assert isinstance(s, annmodel.SomeString)
 
+    def test_unicodeformatting(self):
+        def f(x):
+            return u'%s' % x
+
+        a = self.RPythonAnnotator()
+        s = a.build_types(f, [unicode])
+        assert isinstance(s, annmodel.SomeUnicodeString)
+
+    def test_unicodeformatting_tuple(self):
+        def f(x):
+            return u'%s' % (x,)
+
+        a = self.RPythonAnnotator()
+        s = a.build_types(f, [unicode])
+        assert isinstance(s, annmodel.SomeUnicodeString)
+
 
     def test_negative_slice(self):
         def f(s, e):
@@ -3780,6 +3791,56 @@
         e = py.test.raises(Exception, a.build_types, f, [])
         assert 'object with a __call__ is not RPython' in str(e.value)
 
+    def test_os_getcwd(self):
+        import os
+        def fn():
+            return os.getcwd()
+        a = self.RPythonAnnotator()
+        s = a.build_types(fn, [])
+        assert isinstance(s, annmodel.SomeString)
+        assert s.no_nul
+
+    def test_os_getenv(self):
+        import os
+        def fn():
+            return os.environ.get('PATH')
+        a = self.RPythonAnnotator()
+        s = a.build_types(fn, [])
+        assert isinstance(s, annmodel.SomeString)
+        assert s.no_nul
+
+    def test_base_iter(self):
+        class A(object):
+            def __iter__(self):
+                return self
+        
+        def fn():
+            return iter(A())
+
+        a = self.RPythonAnnotator()
+        s = a.build_types(fn, [])
+        assert isinstance(s, annmodel.SomeInstance)
+        assert s.classdef.name.endswith('.A')
+
+    def test_iter_next(self):
+        class A(object):
+            def __iter__(self):
+                return self
+
+            def next(self):
+                return 1
+        
+        def fn():
+            s = 0
+            for x in A():
+                s += x
+            return s
+
+        a = self.RPythonAnnotator()
+        s = a.build_types(fn, [])
+        assert len(a.translator.graphs) == 3 # fn, __iter__, next
+        assert isinstance(s, annmodel.SomeInteger)
+
 def g(n):
     return [0,1,2,n]
 
diff --git a/pypy/annotation/unaryop.py b/pypy/annotation/unaryop.py
--- a/pypy/annotation/unaryop.py
+++ b/pypy/annotation/unaryop.py
@@ -609,33 +609,36 @@
 
 class __extend__(SomeInstance):
 
+    def _true_getattr(ins, attr):
+        if attr == '__class__':
+            return ins.classdef.read_attr__class__()
+        attrdef = ins.classdef.find_attribute(attr)
+        position = getbookkeeper().position_key
+        attrdef.read_locations[position] = True
+        s_result = attrdef.getvalue()
+        # hack: if s_result is a set of methods, discard the ones
+        #       that can't possibly apply to an instance of ins.classdef.
+        # XXX do it more nicely
+        if isinstance(s_result, SomePBC):
+            s_result = ins.classdef.lookup_filter(s_result, attr,
+                                                  ins.flags)
+        elif isinstance(s_result, SomeImpossibleValue):
+            ins.classdef.check_missing_attribute_update(attr)
+            # blocking is harmless if the attribute is explicitly listed
+            # in the class or a parent class.
+            for basedef in ins.classdef.getmro():
+                if basedef.classdesc.all_enforced_attrs is not None:
+                    if attr in basedef.classdesc.all_enforced_attrs:
+                        raise HarmlesslyBlocked("get enforced attr")
+        elif isinstance(s_result, SomeList):
+            s_result = ins.classdef.classdesc.maybe_return_immutable_list(
+                attr, s_result)
+        return s_result
+
     def getattr(ins, s_attr):
         if s_attr.is_constant() and isinstance(s_attr.const, str):
             attr = s_attr.const
-            if attr == '__class__':
-                return ins.classdef.read_attr__class__()
-            attrdef = ins.classdef.find_attribute(attr)
-            position = getbookkeeper().position_key
-            attrdef.read_locations[position] = True
-            s_result = attrdef.getvalue()
-            # hack: if s_result is a set of methods, discard the ones
-            #       that can't possibly apply to an instance of ins.classdef.
-            # XXX do it more nicely
-            if isinstance(s_result, SomePBC):
-                s_result = ins.classdef.lookup_filter(s_result, attr,
-                                                      ins.flags)
-            elif isinstance(s_result, SomeImpossibleValue):
-                ins.classdef.check_missing_attribute_update(attr)
-                # blocking is harmless if the attribute is explicitly listed
-                # in the class or a parent class.
-                for basedef in ins.classdef.getmro():
-                    if basedef.classdesc.all_enforced_attrs is not None:
-                        if attr in basedef.classdesc.all_enforced_attrs:
-                            raise HarmlesslyBlocked("get enforced attr")
-            elif isinstance(s_result, SomeList):
-                s_result = ins.classdef.classdesc.maybe_return_immutable_list(
-                    attr, s_result)
-            return s_result
+            return ins._true_getattr(attr)
         return SomeObject()
     getattr.can_only_throw = []
 
@@ -657,6 +660,19 @@
         if not ins.can_be_None:
             s.const = True
 
+    def iter(ins):
+        s_iterable = ins._true_getattr('__iter__')
+        bk = getbookkeeper()
+        # record for calltables
+        bk.emulate_pbc_call(bk.position_key, s_iterable, [])
+        return s_iterable.call(bk.build_args("simple_call", []))
+
+    def next(ins):
+        s_next = ins._true_getattr('next')
+        bk = getbookkeeper()
+        # record for calltables
+        bk.emulate_pbc_call(bk.position_key, s_next, [])
+        return s_next.call(bk.build_args("simple_call", []))
 
 class __extend__(SomeBuiltin):
     def _can_only_throw(bltn, *args):
diff --git a/pypy/bin/py.py b/pypy/bin/py.py
--- a/pypy/bin/py.py
+++ b/pypy/bin/py.py
@@ -89,12 +89,12 @@
     space.setitem(space.sys.w_dict, space.wrap('executable'),
                   space.wrap(argv[0]))
 
-    # call pypy_initial_path: the side-effect is that it sets sys.prefix and
+    # call pypy_find_stdlib: the side-effect is that it sets sys.prefix and
     # sys.exec_prefix
-    srcdir = os.path.dirname(os.path.dirname(pypy.__file__))
-    space.appexec([space.wrap(srcdir)], """(srcdir):
+    executable = argv[0]
+    space.appexec([space.wrap(executable)], """(executable):
         import sys
-        sys.pypy_initial_path(srcdir)
+        sys.pypy_find_stdlib(executable)
     """)
 
     # set warning control options (if any)
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -41,6 +41,7 @@
 translation_modules.update(dict.fromkeys(
     ["fcntl", "rctime", "select", "signal", "_rawffi", "zlib",
      "struct", "_md5", "cStringIO", "array", "_ffi",
+     "binascii",
      # the following are needed for pyrepl (and hence for the
      # interactive prompt/pdb)
      "termios", "_minimal_curses",
@@ -79,6 +80,7 @@
 module_dependencies = {
     '_multiprocessing': [('objspace.usemodules.rctime', True),
                          ('objspace.usemodules.thread', True)],
+    'cpyext': [('objspace.usemodules.array', True)],
     }
 module_suggests = {
     # the reason you want _rawffi is for ctypes, which
diff --git a/pypy/config/test/test_pypyoption.py b/pypy/config/test/test_pypyoption.py
--- a/pypy/config/test/test_pypyoption.py
+++ b/pypy/config/test/test_pypyoption.py
@@ -71,7 +71,7 @@
         c = Config(descr)
         for path in c.getpaths(include_groups=True):
             fn = prefix + "." + path + ".txt"
-            yield check_file_exists, fn
+            yield fn, check_file_exists, fn
 
 def test__ffi_opt():
     config = get_pypy_config(translating=True)
diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -99,8 +99,7 @@
                  requires={
                      "shadowstack": [("translation.gctransformer", "framework")],
                      "asmgcc": [("translation.gctransformer", "framework"),
-                                ("translation.backend", "c"),
-                                ("translation.shared", False)],
+                                ("translation.backend", "c")],
                     }),
 
     # other noticeable options
diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst
--- a/pypy/doc/coding-guide.rst
+++ b/pypy/doc/coding-guide.rst
@@ -255,7 +255,12 @@
   code if the translator can prove that they are non-negative.  When
   slicing a string it is necessary to prove that the slice start and
   stop indexes are non-negative. There is no implicit str-to-unicode cast
-  anywhere.
+  anywhere. Simple string formatting using the ``%`` operator works, as long
+  as the format string is known at translation time; the only supported
+  formatting specifiers are ``%s``, ``%d``, ``%x``, ``%o``, ``%f``, plus
+  ``%r`` but only for user-defined instances. Modifiers such as conversion
+  flags, precision, length etc. are not supported. Moreover, it is forbidden
+  to mix unicode and strings when formatting.
 
 **tuples**
 
@@ -341,8 +346,8 @@
 
 **objects**
 
-  Normal rules apply. Special methods are not honoured, except ``__init__`` and
-  ``__del__``.
+  Normal rules apply. Special methods are not honoured, except ``__init__``,
+  ``__del__`` and ``__iter__``.
 
 This layout makes the number of types to take care about quite limited.
 
diff --git a/pypy/doc/config/objspace.usemodules.cppyy.txt b/pypy/doc/config/objspace.usemodules.cppyy.txt
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/objspace.usemodules.cppyy.txt
@@ -0,0 +1,1 @@
+Use the 'cppyy' module
diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
--- a/pypy/doc/cppyy.rst
+++ b/pypy/doc/cppyy.rst
@@ -5,8 +5,10 @@
 The cppyy module provides C++ bindings for PyPy by using the reflection
 information extracted from C++ header files by means of the
 `Reflex package`_.
-For this to work, you have to both install Reflex and build PyPy from the
-reflex-support branch.
+For this to work, you have to both install Reflex and build PyPy from source,
+as the cppyy module is not enabled by default.
+Note that the development version of cppyy lives in the reflex-support
+branch.
 As indicated by this being a branch, support for Reflex is still
 experimental.
 However, it is functional enough to put it in the hands of those who want
@@ -71,7 +73,8 @@
 .. _`recent snapshot`: http://cern.ch/wlav/reflex-2012-05-02.tar.bz2
 .. _`gccxml`: http://www.gccxml.org
 
-Next, get the `PyPy sources`_, select the reflex-support branch, and build.
+Next, get the `PyPy sources`_, optionally select the reflex-support branch,
+and build it.
 For the build to succeed, the ``$ROOTSYS`` environment variable must point to
 the location of your ROOT (or standalone Reflex) installation, or the
 ``root-config`` utility must be accessible through ``PATH`` (e.g. by adding
@@ -82,16 +85,21 @@
 
     $ hg clone https://bitbucket.org/pypy/pypy
     $ cd pypy
-    $ hg up reflex-support
+    $ hg up reflex-support         # optional
     $ cd pypy/translator/goal
+    
+    # This example shows python, but using pypy-c is faster and uses less memory
     $ python translate.py -O jit --gcrootfinder=shadowstack targetpypystandalone.py --withmod-cppyy
 
 This will build a ``pypy-c`` that includes the cppyy module, and through that,
 Reflex support.
 Of course, if you already have a pre-built version of the ``pypy`` interpreter,
 you can use that for the translation rather than ``python``.
+If not, you may want `to obtain a binary distribution`_ to speed up the
+translation step.
 
 .. _`PyPy sources`: https://bitbucket.org/pypy/pypy/overview
+.. _`to obtain a binary distribution`: http://doc.pypy.org/en/latest/getting-started.html#download-a-pre-built-pypy
 
 
 Basic example
@@ -368,6 +376,11 @@
   The C++ side will not see any overridden methods on the python side, as
   cross-inheritance is planned but not yet supported.
 
+* **memory**: C++ instances created by calling their constructor from python
+  are owned by python.
+  You can check/change the ownership with the _python_owns flag that every
+  bound instance carries.
+
 * **methods**: Are represented as python methods and work as expected.
   They are first class objects and can be bound to an instance.
   Virtual C++ methods work as expected.
diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst
--- a/pypy/doc/extending.rst
+++ b/pypy/doc/extending.rst
@@ -23,7 +23,7 @@
 
 * Write them in RPython as mixedmodule_, using *rffi* as bindings.
 
-* Write them in C++ and bind them through Reflex_ (EXPERIMENTAL)
+* Write them in C++ and bind them through Reflex_
 
 .. _ctypes: #CTypes
 .. _\_ffi: #LibFFI
diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst
--- a/pypy/doc/how-to-release.rst
+++ b/pypy/doc/how-to-release.rst
@@ -23,7 +23,9 @@
   some of the next updates may be done before or after branching; make
   sure things are ported back to the trunk and to the branch as
   necessary
-* update pypy/doc/contributor.txt (and possibly LICENSE)
+* update pypy/doc/contributor.rst (and possibly LICENSE)
+* rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst
+  and create a fresh whatsnew_head.rst after the release
 * update README
 * change the tracker to have a new release tag to file bugs against
 * go to pypy/tool/release and run:
diff --git a/pypy/doc/image/agile-talk.jpg b/pypy/doc/image/agile-talk.jpg
deleted file mode 100644
Binary file pypy/doc/image/agile-talk.jpg has changed
diff --git a/pypy/doc/image/architecture-session.jpg b/pypy/doc/image/architecture-session.jpg
deleted file mode 100644
Binary file pypy/doc/image/architecture-session.jpg has changed
diff --git a/pypy/doc/image/bram.jpg b/pypy/doc/image/bram.jpg
deleted file mode 100644
Binary file pypy/doc/image/bram.jpg has changed
diff --git a/pypy/doc/image/coding-discussion.jpg b/pypy/doc/image/coding-discussion.jpg
deleted file mode 100644
Binary file pypy/doc/image/coding-discussion.jpg has changed
diff --git a/pypy/doc/image/guido.jpg b/pypy/doc/image/guido.jpg
deleted file mode 100644
Binary file pypy/doc/image/guido.jpg has changed
diff --git a/pypy/doc/image/interview-bobippolito.jpg b/pypy/doc/image/interview-bobippolito.jpg
deleted file mode 100644
Binary file pypy/doc/image/interview-bobippolito.jpg has changed
diff --git a/pypy/doc/image/interview-timpeters.jpg b/pypy/doc/image/interview-timpeters.jpg
deleted file mode 100644
Binary file pypy/doc/image/interview-timpeters.jpg has changed
diff --git a/pypy/doc/image/introductory-student-talk.jpg b/pypy/doc/image/introductory-student-talk.jpg
deleted file mode 100644
Binary file pypy/doc/image/introductory-student-talk.jpg has changed
diff --git a/pypy/doc/image/introductory-talk-pycon.jpg b/pypy/doc/image/introductory-talk-pycon.jpg
deleted file mode 100644
Binary file pypy/doc/image/introductory-talk-pycon.jpg has changed
diff --git a/pypy/doc/image/ironpython.jpg b/pypy/doc/image/ironpython.jpg
deleted file mode 100644
Binary file pypy/doc/image/ironpython.jpg has changed
diff --git a/pypy/doc/image/mallorca-trailer.jpg b/pypy/doc/image/mallorca-trailer.jpg
deleted file mode 100644
Binary file pypy/doc/image/mallorca-trailer.jpg has changed
diff --git a/pypy/doc/image/pycon-trailer.jpg b/pypy/doc/image/pycon-trailer.jpg
deleted file mode 100644
Binary file pypy/doc/image/pycon-trailer.jpg has changed
diff --git a/pypy/doc/image/sprint-tutorial.jpg b/pypy/doc/image/sprint-tutorial.jpg
deleted file mode 100644
Binary file pypy/doc/image/sprint-tutorial.jpg has changed
diff --git a/pypy/doc/release-1.9.0.rst b/pypy/doc/release-1.9.0.rst
--- a/pypy/doc/release-1.9.0.rst
+++ b/pypy/doc/release-1.9.0.rst
@@ -102,8 +102,8 @@
 JitViewer
 =========
 
-There is a corresponding 1.9 release of JitViewer which is guaranteed to work
-with PyPy 1.9. See the `JitViewer docs`_ for details.
+There will be a corresponding 1.9 release of JitViewer which is guaranteed
+to work with PyPy 1.9. See the `JitViewer docs`_ for details.
 
 .. _`JitViewer docs`: http://bitbucket.org/pypy/jitviewer
 
diff --git a/pypy/doc/video-index.rst b/pypy/doc/video-index.rst
--- a/pypy/doc/video-index.rst
+++ b/pypy/doc/video-index.rst
@@ -2,39 +2,11 @@
 PyPy video documentation 
 =========================
 
-Requirements to download and view
----------------------------------
-
-In order to download the videos you need to point a
-BitTorrent client at the torrent files provided below. 
-We do not provide any other download method at this
-time.  Please get a BitTorrent client (such as bittorrent). 
-For a list of clients please 
-see http://en.wikipedia.org/wiki/Category:Free_BitTorrent_clients or 
-http://en.wikipedia.org/wiki/Comparison_of_BitTorrent_clients. 
-For more information about Bittorrent see 
-http://en.wikipedia.org/wiki/Bittorrent.
-
-In order to view the downloaded movies you need to 
-have a video player that supports DivX AVI files (DivX 5, mp3 audio)
-such as `mplayer`_, `xine`_, `vlc`_ or the windows media player.
-
-.. _`mplayer`: http://www.mplayerhq.hu/design7/dload.html
-.. _`xine`: http://www.xine-project.org
-.. _`vlc`: http://www.videolan.org/vlc/
-
-You can find the necessary codecs in the ffdshow-library:
-http://sourceforge.net/projects/ffdshow/
-
-or use the original divx codec (for Windows):
-http://www.divx.com/software/divx-plus
-
-
 Copyrights and Licensing 
 ----------------------------
 
-The following videos are copyrighted by merlinux gmbh and 
-published under the Creative Commons Attribution License 2.0 Germany: http://creativecommons.org/licenses/by/2.0/de/
+The following videos are copyrighted by merlinux gmbh and available on
+YouTube.
 
 If you need another license, don't hesitate to contact us. 
 
@@ -42,255 +14,202 @@
 Trailer: PyPy at the PyCon 2006
 -------------------------------
 
-130mb: http://buildbot.pypy.org/misc/torrent/pycon-trailer.avi.torrent
+This trailer shows the PyPy team at the PyCon 2006, a behind-the-scenes at
+sprints, talks and everywhere else.
 
-71mb: http://buildbot.pypy.org/misc/torrent/pycon-trailer-medium.avi.torrent
+.. raw:: html
 
-50mb: http://buildbot.pypy.org/misc/torrent/pycon-trailer-320x240.avi.torrent
-
-.. image:: image/pycon-trailer.jpg
-   :scale: 100
-   :alt: Trailer PyPy at PyCon
-   :align: left
-
-This trailer shows the PyPy team at the PyCon 2006, a behind-the-scenes at sprints, talks and everywhere else.
-
-PAL, 9 min, DivX AVI
-
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/WfGszrRUdtc?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Interview with Tim Peters
 -------------------------
 
-440mb: http://buildbot.pypy.org/misc/torrent/interview-timpeters-v2.avi.torrent
+Interview with CPython core developer Tim Peters at PyCon 2006, Dallas,
+US. (2006-03-02)
 
-138mb: http://buildbot.pypy.org/misc/torrent/interview-timpeters-320x240.avi.torrent
+Tim Peters, a longtime CPython core developer talks about how he got into
+Python, what he thinks about the PyPy project and why he thinks it would have
+never been possible in the US.
 
-.. image:: image/interview-timpeters.jpg
-   :scale: 100
-   :alt: Interview with Tim Peters
-   :align: left
+.. raw:: html
 
-Interview with CPython core developer Tim Peters at PyCon 2006, Dallas, US. (2006-03-02)
-
-PAL, 23 min, DivX AVI
-
-Tim Peters, a longtime CPython core developer talks about how he got into Python, what he thinks about the PyPy project and why he thinks it would have never been possible in the US.
-
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/1wAOy88WxmY?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Interview with Bob Ippolito
 ---------------------------
 
-155mb: http://buildbot.pypy.org/misc/torrent/interview-bobippolito-v2.avi.torrent
+What do you think about PyPy? Interview with American software developer Bob
+Ippolito at PyCon 2006, Dallas, US. (2006-03-01)
 
-50mb: http://buildbot.pypy.org/misc/torrent/interview-bobippolito-320x240.avi.torrent
+Bob Ippolito is an Open Source software developer from San Francisco and has
+been to two PyPy sprints. In this interview he is giving his opinion on the
+project.
 
-.. image:: image/interview-bobippolito.jpg
-   :scale: 100
-   :alt: Interview with Bob Ippolito
-   :align: left
+.. raw:: html
 
-What do you think about PyPy? Interview with American software developer Bob Ippolito at tPyCon 2006, Dallas, US. (2006-03-01)
-
-PAL 8 min, DivX AVI
-
-Bob Ippolito is an Open Source software developer from San Francisco and has been to two PyPy sprints. In this interview he is giving his opinion on the project.
-
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/c5rq4Q03zgg?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Introductory talk on PyPy
 -------------------------
 
-430mb: http://buildbot.pypy.org/misc/torrent/introductory-talk-pycon-v1.avi.torrent
-
-166mb: http://buildbot.pypy.org/misc/torrent/introductory-talk-pycon-320x240.avi.torrent
-
-.. image:: image/introductory-talk-pycon.jpg
-   :scale: 100
-   :alt: Introductory talk at PyCon 2006
-   :align: left
-
-This introductory talk is given by core developers Michael Hudson and Christian Tismer at PyCon 2006, Dallas, US. (2006-02-26)
-
-PAL, 28 min, divx AVI
+This introductory talk is given by core developers Michael Hudson and
+Christian Tismer at PyCon 2006, Dallas, US. (2006-02-26)
 
 Michael Hudson talks about the basic building blocks of Python, the currently
 available back-ends, and the status of PyPy in general. Christian Tismer takes
-over to explain how co-routines can be used to implement things like
-Stackless and Greenlets in PyPy.
+over to explain how co-routines can be used to implement things like Stackless
+and Greenlets in PyPy.
 
+.. raw:: html
+
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/AWUhXW2pLDE?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Talk on Agile Open Source Methods in the PyPy project
 -----------------------------------------------------
 
-395mb: http://buildbot.pypy.org/misc/torrent/agile-talk-v1.avi.torrent
-
-153mb: http://buildbot.pypy.org/misc/torrent/agile-talk-320x240.avi.torrent
-
-.. image:: image/agile-talk.jpg
-   :scale: 100
-   :alt: Agile talk
-   :align: left
-
-Core developer Holger Krekel and project manager Beatrice During are giving a talk on the agile open source methods used in the PyPy project at PyCon 2006, Dallas, US. (2006-02-26)
-
-PAL, 26 min, divx AVI
+Core developer Holger Krekel and project manager Beatrice During are giving a
+talk on the agile open source methods used in the PyPy project at PyCon 2006,
+Dallas, US. (2006-02-26)
 
 Holger Krekel explains more about the goals and history of PyPy, and the
 structure and organization behind it. Bea During describes the intricacies of
 driving a distributed community in an agile way, and how to combine that with
 the formalities required for EU funding.
 
+.. raw:: html
+
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/ed-zAxZtGlY?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 PyPy Architecture session
 -------------------------
 
-744mb: http://buildbot.pypy.org/misc/torrent/architecture-session-v1.avi.torrent
-
-288mb: http://buildbot.pypy.org/misc/torrent/architecture-session-320x240.avi.torrent
-
-.. image:: image/architecture-session.jpg
-   :scale: 100
-   :alt: Architecture session
-   :align: left
-
-This architecture session is given by core developers Holger Krekel and Armin Rigo at PyCon 2006, Dallas, US. (2006-02-26)
-
-PAL, 48 min, divx AVI
+This architecture session is given by core developers Holger Krekel and Armin
+Rigo at PyCon 2006, Dallas, US. (2006-02-26)
 
 Holger Krekel and Armin Rigo talk about the basic implementation,
-implementation level aspects and the RPython translation toolchain. This
-talk also gives an insight into how a developer works with these tools on
-a daily basis, and pays special attention to flow graphs.
+implementation level aspects and the RPython translation toolchain. This talk
+also gives an insight into how a developer works with these tools on a daily
+basis, and pays special attention to flow graphs.
 
+.. raw:: html
+
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/7opXGaQUUA4?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Sprint tutorial
 ---------------
 
-680mb: http://buildbot.pypy.org/misc/torrent/sprint-tutorial-v2.avi.torrent
+Sprint tutorial by core developer Michael Hudson at PyCon 2006, Dallas,
+US. (2006-02-27)
 
-263mb: http://buildbot.pypy.org/misc/torrent/sprint-tutorial-320x240.avi.torrent
+Michael Hudson gives an in-depth, very technical introduction to a PyPy
+sprint. The film provides a detailed and hands-on overview about the
+architecture of PyPy, especially the RPython translation toolchain.
 
-.. image:: image/sprint-tutorial.jpg
-   :scale: 100
-   :alt: Sprint Tutorial
-   :align: left
+.. raw:: html
 
-Sprint tutorial by core developer Michael Hudson at PyCon 2006, Dallas, US. (2006-02-27)
-
-PAL, 44 min, divx AVI
-
-Michael Hudson gives an in-depth, very technical introduction to a PyPy sprint. The film provides a detailed and hands-on overview about the architecture of PyPy, especially the RPython translation toolchain.
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/1YV7J74xrMI?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Scripting .NET with IronPython by Jim Hugunin
 ---------------------------------------------
 
-372mb: http://buildbot.pypy.org/misc/torrent/ironpython-talk-v2.avi.torrent
+Talk by Jim Hugunin (Microsoft) on the IronPython implementation on the .NET
+framework at the PyCon 2006, Dallas, US.
 
-270mb: http://buildbot.pypy.org/misc/torrent/ironpython-talk-320x240.avi.torrent
+Jim Hugunin talks about regression tests, the code generation and the object
+layout, the new-style instance and gives a CLS interop demo.
 
-.. image:: image/ironpython.jpg
-   :scale: 100
-   :alt: Jim Hugunin on IronPython
-   :align: left
+.. raw:: html
 
-Talk by Jim Hugunin (Microsoft) on the IronPython implementation on the .NET framework at this years PyCon, Dallas, US.
-
-PAL, 44 min, DivX AVI
-
-Jim Hugunin talks about regression tests, the code generation and the object layout, the new-style instance and gives a CLS interop demo.
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/bq9ZGN3-o80?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Bram Cohen, founder and developer of BitTorrent
 -----------------------------------------------
 
-509mb: http://buildbot.pypy.org/misc/torrent/bram-cohen-interview-v1.avi.torrent
+Bram Cohen is interviewed by Steve Holden at the PyCon 2006, Dallas, US.
 
-370mb: http://buildbot.pypy.org/misc/torrent/bram-cohen-interview-320x240.avi.torrent
+.. raw:: html
 
-.. image:: image/bram.jpg
-   :scale: 100
-   :alt: Bram Cohen on BitTorrent
-   :align: left
-
-Bram Cohen is interviewed by Steve Holden at this years PyCon, Dallas, US.
-
-PAL, 60 min, DivX AVI
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/EopmJWrLmWI?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Keynote speech by Guido van Rossum on the new Python 2.5 features
 -----------------------------------------------------------------
 
-695mb: http://buildbot.pypy.org/misc/torrent/keynote-speech_guido-van-rossum_v1.avi.torrent
+Guido van Rossum explains the new Python 2.5 features at the PyCon 2006,
+Dallas, US.
 
-430mb: http://buildbot.pypy.org/misc/torrent/keynote-speech_guido-van-rossum_320x240.avi.torrent
+.. raw:: html
 
-.. image:: image/guido.jpg
-   :scale: 100
-   :alt: Guido van Rossum on Python 2.5
-   :align: left
-
-Guido van Rossum explains the new Python 2.5 features at this years PyCon, Dallas, US.
-
-PAL, 70 min, DivX AVI
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/RR2sX8tFGsI?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Trailer: PyPy sprint at the University of Palma de Mallorca
 -----------------------------------------------------------
 
-166mb: http://buildbot.pypy.org/misc/torrent/mallorca-trailer-v1.avi.torrent
+This trailer shows the PyPy team at the sprint in Mallorca, a
+behind-the-scenes of a typical PyPy coding sprint and talk as well as
+everything else.
 
-88mb: http://buildbot.pypy.org/misc/torrent/mallorca-trailer-medium.avi.torrent
+.. raw:: html
 
-64mb: http://buildbot.pypy.org/misc/torrent/mallorca-trailer-320x240.avi.torrent
-
-.. image:: image/mallorca-trailer.jpg
-   :scale: 100
-   :alt: Trailer PyPy sprint in Mallorca
-   :align: left
-
-This trailer shows the PyPy team at the sprint in Mallorca, a behind-the-scenes of a typical PyPy coding sprint and talk as well as everything else.
-
-PAL, 11 min, DivX AVI
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/swsnRfj_cek?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Coding discussion of core developers Armin Rigo and Samuele Pedroni
 -------------------------------------------------------------------
 
-620mb: http://buildbot.pypy.org/misc/torrent/coding-discussion-v1.avi.torrent
+Coding discussion between Armin Rigo and Samuele Pedroni during the PyPy
+sprint at the University of Palma de Mallorca, Spain. 27.1.2006
 
-240mb: http://buildbot.pypy.org/misc/torrent/coding-discussion-320x240.avi.torrent
+.. raw:: html
 
-.. image:: image/coding-discussion.jpg
-   :scale: 100
-   :alt: Coding discussion
-   :align: left
-
-Coding discussion between Armin Rigo and Samuele Pedroni during the PyPy sprint at the University of Palma de Mallorca, Spain. 27.1.2006
-
-PAL 40 min, DivX AVI
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/H_IgK9qmEss?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 PyPy technical talk at the University of Palma de Mallorca
 ----------------------------------------------------------
 
-865mb: http://buildbot.pypy.org/misc/torrent/introductory-student-talk-v2.avi.torrent
-
-437mb: http://buildbot.pypy.org/misc/torrent/introductory-student-talk-320x240.avi.torrent
-
-.. image:: image/introductory-student-talk.jpg
-   :scale: 100
-   :alt: Introductory student talk
-   :align: left
-
 Technical talk on the PyPy project at the University of Palma de Mallorca, Spain. 27.1.2006
 
-PAL 72 min, DivX AVI
+Core developers Armin Rigo, Samuele Pedroni and Carl Friedrich Bolz are giving
+an overview of the PyPy architecture, the standard interpreter, the RPython
+translation toolchain and the just-in-time compiler.
 
-Core developers Armin Rigo, Samuele Pedroni and Carl Friedrich Bolz are giving an overview of the PyPy architecture, the standard interpreter, the RPython translation toolchain and the just-in-time compiler.
+.. raw:: html
 
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/6dnUzVQaSlg?rel=0"
+   frameborder="0" allowfullscreen></iframe>
+
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/whatsnew-head.rst
@@ -0,0 +1,31 @@
+======================
+What's new in PyPy xxx
+======================
+
+.. this is the revision of the last merge from default to release-1.9.x
+.. startrev: 8d567513d04d
+
+.. branch: default
+.. branch: app_main-refactor
+.. branch: win-ordinal
+.. branch: reflex-support
+Provides cppyy module (disabled by default) for access to C++ through Reflex.
+See doc/cppyy.rst for full details and functionality.
+.. branch: nupypy-axis-arg-check
+Check that axis arg is valid in _numpypy
+
+.. branch: iterator-in-rpython
+.. branch: numpypy_count_nonzero
+.. branch: even-more-jit-hooks
+Implement better JIT hooks
+.. branch: virtual-arguments
+Improve handling of **kwds greatly, making them virtual sometimes.
+.. branch: improve-rbigint
+Introduce __int128 on systems where it's supported and improve the speed of
+rlib/rbigint.py greatly.
+
+.. "uninteresting" branches that we should just ignore for the whatsnew:
+.. branch: slightly-shorter-c
+.. branch: better-enforceargs
+.. branch: rpython-unicode-formatting
+.. branch: jit-opaque-licm
diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py
--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -110,12 +110,10 @@
             make_sure_not_resized(self.keywords_w)
 
         make_sure_not_resized(self.arguments_w)
-        if w_stararg is not None:
-            self._combine_starargs_wrapped(w_stararg)
-        # if we have a call where **args are used at the callsite
-        # we shouldn't let the JIT see the argument matching
-        self._dont_jit = (w_starstararg is not None and
-                          self._combine_starstarargs_wrapped(w_starstararg))
+        self._combine_wrapped(w_stararg, w_starstararg)
+        # a flag that specifies whether the JIT can unroll loops that operate
+        # on the keywords
+        self._jit_few_keywords = self.keywords is None or jit.isconstant(len(self.keywords))
 
     def __repr__(self):
         """ NOT_RPYTHON """
@@ -129,7 +127,7 @@
 
     ###  Manipulation  ###
 
-    @jit.look_inside_iff(lambda self: not self._dont_jit)
+    @jit.look_inside_iff(lambda self: self._jit_few_keywords)
     def unpack(self): # slowish
         "Return a ([w1,w2...], {'kw':w3...}) pair."
         kwds_w = {}
@@ -176,13 +174,14 @@
         keywords, values_w = space.view_as_kwargs(w_starstararg)
         if keywords is not None: # this path also taken for empty dicts
             if self.keywords is None:
-                self.keywords = keywords[:] # copy to make non-resizable
-                self.keywords_w = values_w[:]
+                self.keywords = keywords
+                self.keywords_w = values_w
             else:
-                self._check_not_duplicate_kwargs(keywords, values_w)
+                _check_not_duplicate_kwargs(
+                    self.space, self.keywords, keywords, values_w)
                 self.keywords = self.keywords + keywords
                 self.keywords_w = self.keywords_w + values_w
-            return not jit.isconstant(len(self.keywords))
+            return
         if space.isinstance_w(w_starstararg, space.w_dict):
             keys_w = space.unpackiterable(w_starstararg)
         else:
@@ -198,57 +197,17 @@
                                    "a mapping, not %s" % (typename,)))
                 raise
             keys_w = space.unpackiterable(w_keys)
-        self._do_combine_starstarargs_wrapped(keys_w, w_starstararg)
-        return True
-
-    def _do_combine_starstarargs_wrapped(self, keys_w, w_starstararg):
-        space = self.space
         keywords_w = [None] * len(keys_w)
         keywords = [None] * len(keys_w)
-        i = 0
-        for w_key in keys_w:
-            try:
-                key = space.str_w(w_key)
-            except OperationError, e:
-                if e.match(space, space.w_TypeError):
-                    raise OperationError(
-                        space.w_TypeError,
-                        space.wrap("keywords must be strings"))
-                if e.match(space, space.w_UnicodeEncodeError):
-                    # Allow this to pass through
-                    key = None
-                else:
-                    raise
-            else:
-                if self.keywords and key in self.keywords:
-                    raise operationerrfmt(self.space.w_TypeError,
-                                          "got multiple values "
-                                          "for keyword argument "
-                                          "'%s'", key)
-            keywords[i] = key
-            keywords_w[i] = space.getitem(w_starstararg, w_key)
-            i += 1
+        _do_combine_starstarargs_wrapped(space, keys_w, w_starstararg, keywords, keywords_w, self.keywords)
+        self.keyword_names_w = keys_w
         if self.keywords is None:
             self.keywords = keywords
             self.keywords_w = keywords_w
         else:
             self.keywords = self.keywords + keywords
             self.keywords_w = self.keywords_w + keywords_w
-        self.keyword_names_w = keys_w
 
-    @jit.look_inside_iff(lambda self, keywords, keywords_w:
-            jit.isconstant(len(keywords) and
-            jit.isconstant(self.keywords)))
-    def _check_not_duplicate_kwargs(self, keywords, keywords_w):
-        # looks quadratic, but the JIT should remove all of it nicely.
-        # Also, all the lists should be small
-        for key in keywords:
-            for otherkey in self.keywords:
-                if otherkey == key:
-                    raise operationerrfmt(self.space.w_TypeError,
-                                          "got multiple values "
-                                          "for keyword argument "
-                                          "'%s'", key)
 
     def fixedunpack(self, argcount):
         """The simplest argument parsing: get the 'argcount' arguments,
@@ -269,34 +228,14 @@
 
     ###  Parsing for function calls  ###
 
-    # XXX: this should be @jit.look_inside_iff, but we need key word arguments,
-    # and it doesn't support them for now.
+    @jit.unroll_safe
     def _match_signature(self, w_firstarg, scope_w, signature, defaults_w=None,
                          blindargs=0):
         """Parse args and kwargs according to the signature of a code object,
         or raise an ArgErr in case of failure.
-        Return the number of arguments filled in.
         """
-        if jit.we_are_jitted() and self._dont_jit:
-            return self._match_signature_jit_opaque(w_firstarg, scope_w,
-                                                    signature, defaults_w,
-                                                    blindargs)
-        return self._really_match_signature(w_firstarg, scope_w, signature,
-                                            defaults_w, blindargs)
-
-    @jit.dont_look_inside
-    def _match_signature_jit_opaque(self, w_firstarg, scope_w, signature,
-                                    defaults_w, blindargs):
-        return self._really_match_signature(w_firstarg, scope_w, signature,
-                                            defaults_w, blindargs)
-
-    @jit.unroll_safe
-    def _really_match_signature(self, w_firstarg, scope_w, signature,
-                                defaults_w=None, blindargs=0):
-        #
+        #   w_firstarg = a first argument to be inserted (e.g. self) or None
         #   args_w = list of the normal actual parameters, wrapped
-        #   kwds_w = real dictionary {'keyword': wrapped parameter}
-        #   argnames = list of formal parameter names
         #   scope_w = resulting list of wrapped values
         #
 
@@ -304,38 +243,29 @@
         # so all values coming from there can be assumed constant. It assumes
         # that the length of the defaults_w does not vary too much.
         co_argcount = signature.num_argnames() # expected formal arguments, without */**
-        has_vararg = signature.has_vararg()
-        has_kwarg = signature.has_kwarg()
-        extravarargs = None
-        input_argcount =  0
 
+        # put the special w_firstarg into the scope, if it exists
         if w_firstarg is not None:
             upfront = 1
             if co_argcount > 0:
                 scope_w[0] = w_firstarg
-                input_argcount = 1
-            else:
-                extravarargs = [w_firstarg]
         else:
             upfront = 0
 
         args_w = self.arguments_w
         num_args = len(args_w)
+        avail = num_args + upfront
 
         keywords = self.keywords
-        keywords_w = self.keywords_w
         num_kwds = 0
         if keywords is not None:
             num_kwds = len(keywords)
 
-        avail = num_args + upfront
 
+        # put as many positional input arguments into place as available
+        input_argcount = upfront
         if input_argcount < co_argcount:
-            # put as many positional input arguments into place as available
-            if avail > co_argcount:
-                take = co_argcount - input_argcount
-            else:
-                take = num_args
+            take = min(num_args, co_argcount - upfront)
 
             # letting the JIT unroll this loop is safe, because take is always
             # smaller than co_argcount
@@ -344,11 +274,10 @@
             input_argcount += take
 
         # collect extra positional arguments into the *vararg
-        if has_vararg:
+        if signature.has_vararg():
             args_left = co_argcount - upfront
             if args_left < 0:  # check required by rpython
-                assert extravarargs is not None
-                starargs_w = extravarargs
+                starargs_w = [w_firstarg]
                 if num_args:
                     starargs_w = starargs_w + args_w
             elif num_args > args_left:
@@ -357,86 +286,68 @@
                 starargs_w = []
             scope_w[co_argcount] = self.space.newtuple(starargs_w)
         elif avail > co_argcount:
-            raise ArgErrCount(avail, num_kwds,
-                              co_argcount, has_vararg, has_kwarg,
-                              defaults_w, 0)
+            raise ArgErrCount(avail, num_kwds, signature, defaults_w, 0)
 
-        # the code assumes that keywords can potentially be large, but that
-        # argnames is typically not too large
-        num_remainingkwds = num_kwds
-        used_keywords = None
-        if keywords:
-            # letting JIT unroll the loop is *only* safe if the callsite didn't
-            # use **args because num_kwds can be arbitrarily large otherwise.
-            used_keywords = [False] * num_kwds
-            for i in range(num_kwds):
-                name = keywords[i]
-                # If name was not encoded as a string, it could be None. In that
-                # case, it's definitely not going to be in the signature.
-                if name is None:
-                    continue
-                j = signature.find_argname(name)
-                if j < 0:
-                    continue
-                elif j < input_argcount:
-                    # check that no keyword argument conflicts with these. note
-                    # that for this purpose we ignore the first blindargs,
-                    # which were put into place by prepend().  This way,
-                    # keywords do not conflict with the hidden extra argument
-                    # bound by methods.
-                    if blindargs <= j:
-                        raise ArgErrMultipleValues(name)
+        # if a **kwargs argument is needed, create the dict
+        w_kwds = None
+        if signature.has_kwarg():
+            w_kwds = self.space.newdict(kwargs=True)
+            scope_w[co_argcount + signature.has_vararg()] = w_kwds
+
+        # handle keyword arguments
+        num_remainingkwds = 0
+        keywords_w = self.keywords_w
+        kwds_mapping = None
+        if num_kwds:
+            # kwds_mapping maps target indexes in the scope (minus input_argcount)
+            # to positions in the keywords_w list
+            cnt = (co_argcount - input_argcount)
+            if cnt < 0:
+                cnt = 0
+            kwds_mapping = [0] * cnt
+            # initialize manually, for the JIT :-(
+            for i in range(len(kwds_mapping)):
+                kwds_mapping[i] = -1
+            # match the keywords given at the call site to the argument names
+            # the called function takes
+            # this function must not take a scope_w, to make the scope not
+            # escape
+            num_remainingkwds = _match_keywords(
+                    signature, blindargs, input_argcount, keywords,
+                    kwds_mapping, self._jit_few_keywords)
+            if num_remainingkwds:
+                if w_kwds is not None:
+                    # collect extra keyword arguments into the **kwarg
+                    _collect_keyword_args(
+                            self.space, keywords, keywords_w, w_kwds,
+                            kwds_mapping, self.keyword_names_w, self._jit_few_keywords)
                 else:
-                    assert scope_w[j] is None
-                    scope_w[j] = keywords_w[i]
-                    used_keywords[i] = True # mark as used
-                    num_remainingkwds -= 1
+                    if co_argcount == 0:
+                        raise ArgErrCount(avail, num_kwds, signature, defaults_w, 0)
+                    raise ArgErrUnknownKwds(self.space, num_remainingkwds, keywords,
+                                            kwds_mapping, self.keyword_names_w)
+
+        # check for missing arguments and fill them from the kwds,
+        # or with defaults, if available
         missing = 0
         if input_argcount < co_argcount:
             def_first = co_argcount - (0 if defaults_w is None else len(defaults_w))
+            j = 0
+            kwds_index = -1
             for i in range(input_argcount, co_argcount):
-                if scope_w[i] is not None:
-                    continue
+                if kwds_mapping is not None:
+                    kwds_index = kwds_mapping[j]
+                    j += 1
+                    if kwds_index >= 0:
+                        scope_w[i] = keywords_w[kwds_index]
+                        continue
                 defnum = i - def_first
                 if defnum >= 0:
                     scope_w[i] = defaults_w[defnum]
                 else:
-                    # error: not enough arguments.  Don't signal it immediately
-                    # because it might be related to a problem with */** or
-                    # keyword arguments, which will be checked for below.
                     missing += 1
-
-        # collect extra keyword arguments into the **kwarg
-        if has_kwarg:
-            w_kwds = self.space.newdict(kwargs=True)
-            if num_remainingkwds:
-                #
-                limit = len(keywords)
-                if self.keyword_names_w is not None:
-                    limit -= len(self.keyword_names_w)
-                for i in range(len(keywords)):
-                    if not used_keywords[i]:
-                        if i < limit:
-                            w_key = self.space.wrap(keywords[i])
-                        else:
-                            w_key = self.keyword_names_w[i - limit]
-                        self.space.setitem(w_kwds, w_key, keywords_w[i])
-                #
-            scope_w[co_argcount + has_vararg] = w_kwds
-        elif num_remainingkwds:
-            if co_argcount == 0:
-                raise ArgErrCount(avail, num_kwds,
-                              co_argcount, has_vararg, has_kwarg,
-                              defaults_w, missing)
-            raise ArgErrUnknownKwds(self.space, num_remainingkwds, keywords,
-                                    used_keywords, self.keyword_names_w)
-
-        if missing:
-            raise ArgErrCount(avail, num_kwds,
-                              co_argcount, has_vararg, has_kwarg,
-                              defaults_w, missing)
-
-        return co_argcount + has_vararg + has_kwarg
+            if missing:
+                raise ArgErrCount(avail, num_kwds, signature, defaults_w, missing)
 
 
 
@@ -448,11 +359,12 @@
         scope_w must be big enough for signature.
         """
         try:
-            return self._match_signature(w_firstarg,
-                                         scope_w, signature, defaults_w, 0)
+            self._match_signature(w_firstarg,
+                                  scope_w, signature, defaults_w, 0)
         except ArgErr, e:
             raise operationerrfmt(self.space.w_TypeError,
                                   "%s() %s", fnname, e.getmsg())
+        return signature.scope_length()
 
     def _parse(self, w_firstarg, signature, defaults_w, blindargs=0):
         """Parse args and kwargs according to the signature of a code object,
@@ -499,6 +411,102 @@
                 space.setitem(w_kwds, w_key, self.keywords_w[i])
         return w_args, w_kwds
 
+# JIT helper functions
+# these functions contain functionality that the JIT is not always supposed to
+# look at. They should not get a self arguments, which makes the amount of
+# arguments annoying :-(
+
+ at jit.look_inside_iff(lambda space, existingkeywords, keywords, keywords_w:
+        jit.isconstant(len(keywords) and
+        jit.isconstant(existingkeywords)))
+def _check_not_duplicate_kwargs(space, existingkeywords, keywords, keywords_w):
+    # looks quadratic, but the JIT should remove all of it nicely.
+    # Also, all the lists should be small
+    for key in keywords:
+        for otherkey in existingkeywords:
+            if otherkey == key:
+                raise operationerrfmt(space.w_TypeError,
+                                      "got multiple values "
+                                      "for keyword argument "
+                                      "'%s'", key)
+
+def _do_combine_starstarargs_wrapped(space, keys_w, w_starstararg, keywords,
+        keywords_w, existingkeywords):
+    i = 0
+    for w_key in keys_w:
+        try:
+            key = space.str_w(w_key)
+        except OperationError, e:
+            if e.match(space, space.w_TypeError):
+                raise OperationError(
+                    space.w_TypeError,
+                    space.wrap("keywords must be strings"))
+            if e.match(space, space.w_UnicodeEncodeError):
+                # Allow this to pass through
+                key = None
+            else:
+                raise
+        else:
+            if existingkeywords and key in existingkeywords:
+                raise operationerrfmt(space.w_TypeError,
+                                      "got multiple values "
+                                      "for keyword argument "
+                                      "'%s'", key)
+        keywords[i] = key
+        keywords_w[i] = space.getitem(w_starstararg, w_key)
+        i += 1
+
+ at jit.look_inside_iff(
+    lambda signature, blindargs, input_argcount,
+           keywords, kwds_mapping, jiton: jiton)
+def _match_keywords(signature, blindargs, input_argcount,
+                    keywords, kwds_mapping, _):
+    # letting JIT unroll the loop is *only* safe if the callsite didn't
+    # use **args because num_kwds can be arbitrarily large otherwise.
+    num_kwds = num_remainingkwds = len(keywords)
+    for i in range(num_kwds):
+        name = keywords[i]
+        # If name was not encoded as a string, it could be None. In that
+        # case, it's definitely not going to be in the signature.
+        if name is None:
+            continue
+        j = signature.find_argname(name)
+        # if j == -1 nothing happens, because j < input_argcount and
+        # blindargs > j
+        if j < input_argcount:
+            # check that no keyword argument conflicts with these. note
+            # that for this purpose we ignore the first blindargs,
+            # which were put into place by prepend().  This way,
+            # keywords do not conflict with the hidden extra argument
+            # bound by methods.
+            if blindargs <= j:
+                raise ArgErrMultipleValues(name)
+        else:
+            kwds_mapping[j - input_argcount] = i # map to the right index
+            num_remainingkwds -= 1
+    return num_remainingkwds
+
+ at jit.look_inside_iff(
+    lambda space, keywords, keywords_w, w_kwds, kwds_mapping,
+        keyword_names_w, jiton: jiton)
+def _collect_keyword_args(space, keywords, keywords_w, w_kwds, kwds_mapping,
+                          keyword_names_w, _):
+    limit = len(keywords)
+    if keyword_names_w is not None:
+        limit -= len(keyword_names_w)
+    for i in range(len(keywords)):
+        # again a dangerous-looking loop that either the JIT unrolls
+        # or that is not too bad, because len(kwds_mapping) is small
+        for j in kwds_mapping:
+            if i == j:
+                break
+        else:
+            if i < limit:
+                w_key = space.wrap(keywords[i])
+            else:
+                w_key = keyword_names_w[i - limit]
+            space.setitem(w_kwds, w_key, keywords_w[i])
+
 class ArgumentsForTranslation(Arguments):
     def __init__(self, space, args_w, keywords=None, keywords_w=None,
                  w_stararg=None, w_starstararg=None):
@@ -654,11 +662,9 @@
 
 class ArgErrCount(ArgErr):
 
-    def __init__(self, got_nargs, nkwds, expected_nargs, has_vararg, has_kwarg,
+    def __init__(self, got_nargs, nkwds, signature,
                  defaults_w, missing_args):
-        self.expected_nargs = expected_nargs
-        self.has_vararg = has_vararg
-        self.has_kwarg = has_kwarg
+        self.signature = signature
 
         self.num_defaults = 0 if defaults_w is None else len(defaults_w)
         self.missing_args = missing_args
@@ -666,16 +672,16 @@
         self.num_kwds = nkwds
 
     def getmsg(self):
-        n = self.expected_nargs
+        n = self.signature.num_argnames()
         if n == 0:
             msg = "takes no arguments (%d given)" % (
                 self.num_args + self.num_kwds)
         else:
             defcount = self.num_defaults
-            has_kwarg = self.has_kwarg
+            has_kwarg = self.signature.has_kwarg()
             num_args = self.num_args
             num_kwds = self.num_kwds
-            if defcount == 0 and not self.has_vararg:
+            if defcount == 0 and not self.signature.has_vararg():
                 msg1 = "exactly"
                 if not has_kwarg:
                     num_args += num_kwds
@@ -714,13 +720,13 @@
 
 class ArgErrUnknownKwds(ArgErr):
 
-    def __init__(self, space, num_remainingkwds, keywords, used_keywords,
+    def __init__(self, space, num_remainingkwds, keywords, kwds_mapping,
                  keyword_names_w):
         name = ''
         self.num_kwds = num_remainingkwds
         if num_remainingkwds == 1:
             for i in range(len(keywords)):
-                if not used_keywords[i]:
+                if i not in kwds_mapping:
                     name = keywords[i]
                     if name is None:
                         # We'll assume it's unicode. Encode it.
diff --git a/pypy/interpreter/astcompiler/test/test_astbuilder.py b/pypy/interpreter/astcompiler/test/test_astbuilder.py
--- a/pypy/interpreter/astcompiler/test/test_astbuilder.py
+++ b/pypy/interpreter/astcompiler/test/test_astbuilder.py
@@ -1105,6 +1105,17 @@
         assert isinstance(s, ast.Str)
         assert space.eq_w(s.s, space.wrap(sentence))
 
+    def test_string_bug(self):
+        space = self.space
+        source = '# -*- encoding: utf8 -*-\nstuff = "x \xc3\xa9 \\n"\n'
+        info = pyparse.CompileInfo("<test>", "exec")
+        tree = self.parser.parse_source(source, info)
+        assert info.encoding == "utf8"
+        s = ast_from_node(space, tree, info).body[0].value
+        assert isinstance(s, ast.Str)
+        expected = ['x', ' ', chr(0xc3), chr(0xa9), ' ', '\n']
+        assert space.eq_w(s.s, space.wrap(''.join(expected)))
+
     def test_number(self):
         def get_num(s):
             node = self.get_first_expr(s)
diff --git a/pypy/interpreter/buffer.py b/pypy/interpreter/buffer.py
--- a/pypy/interpreter/buffer.py
+++ b/pypy/interpreter/buffer.py
@@ -44,6 +44,9 @@
         # May be overridden.  No bounds checks.
         return ''.join([self.getitem(i) for i in range(start, stop, step)])
 
+    def get_raw_address(self):
+        raise ValueError("no raw buffer")
+
     # __________ app-level support __________
 
     def descr_len(self, space):
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -496,7 +496,12 @@
 
     # apply kw_spec
     for name, spec in kw_spec.items():
-        unwrap_spec[argnames.index(name)] = spec
+        try:
+            unwrap_spec[argnames.index(name)] = spec
+        except ValueError:
+            raise ValueError("unwrap_spec() got a keyword %r but it is not "
+                             "the name of an argument of the following "
+                             "function" % (name,))
 
     return unwrap_spec
 
diff --git a/pypy/interpreter/pyparser/parsestring.py b/pypy/interpreter/pyparser/parsestring.py
--- a/pypy/interpreter/pyparser/parsestring.py
+++ b/pypy/interpreter/pyparser/parsestring.py
@@ -97,7 +97,8 @@
         return space.wrap(v)
 
     need_encoding = (encoding is not None and
-                     encoding != "utf-8" and encoding != "iso-8859-1")
+                     encoding != "utf-8" and encoding != "utf8" and
+                     encoding != "iso-8859-1")
     assert 0 <= ps <= q
     substr = s[ps : q]
     if rawmode or '\\' not in s[ps:]:
@@ -129,19 +130,18 @@
     builder = StringBuilder(len(s))
     ps = 0
     end = len(s)
-    while 1:
-        ps2 = ps
-        while ps < end and s[ps] != '\\':
+    while ps < end:
+        if s[ps] != '\\':
+            # note that the C code has a label here.
+            # the logic is the same.
             if recode_encoding and ord(s[ps]) & 0x80:
                 w, ps = decode_utf8(space, s, ps, end, recode_encoding)
+                # Append bytes to output buffer.
                 builder.append(w)
-                ps2 = ps
             else:
+                builder.append(s[ps])
                 ps += 1
-        if ps > ps2:
-            builder.append_slice(s, ps2, ps)
-        if ps == end:
-            break
+            continue
 
         ps += 1
         if ps == end:
diff --git a/pypy/interpreter/pyparser/test/test_parsestring.py b/pypy/interpreter/pyparser/test/test_parsestring.py
--- a/pypy/interpreter/pyparser/test/test_parsestring.py
+++ b/pypy/interpreter/pyparser/test/test_parsestring.py
@@ -84,3 +84,10 @@
         s = '"""' + '\\' + '\n"""'
         w_ret = parsestring.parsestr(space, None, s)
         assert space.str_w(w_ret) == ''
+
+    def test_bug1(self):
+        space = self.space
+        expected = ['x', ' ', chr(0xc3), chr(0xa9), ' ', '\n']
+        input = ["'", 'x', ' ', chr(0xc3), chr(0xa9), ' ', chr(92), 'n', "'"]
+        w_ret = parsestring.parsestr(space, 'utf8', ''.join(input))
+        assert space.str_w(w_ret) == ''.join(expected)
diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py
--- a/pypy/interpreter/test/test_argument.py
+++ b/pypy/interpreter/test/test_argument.py
@@ -57,6 +57,9 @@
     def __nonzero__(self):
         raise NotImplementedError
 
+class kwargsdict(dict):
+    pass
+
 class DummySpace(object):
     def newtuple(self, items):
         return tuple(items)
@@ -76,9 +79,13 @@
         return list(it)
 
     def view_as_kwargs(self, x):
+        if len(x) == 0:
+            return [], []
         return None, None
 
     def newdict(self, kwargs=False):
+        if kwargs:
+            return kwargsdict()
         return {}
 
     def newlist(self, l=[]):
@@ -299,6 +306,22 @@
             args._match_signature(None, l, Signature(["a", "b", "c"], None, "**"))
             assert l == [1, 2, 3, {'d': 4}]
 
+    def test_match_kwds_creates_kwdict(self):
+        space = DummySpace()
+        kwds = [("c", 3), ('d', 4)]
+        for i in range(4):
+            kwds_w = dict(kwds[:i])
+            keywords = kwds_w.keys()
+            keywords_w = kwds_w.values()
+            w_kwds = dummy_wrapped_dict(kwds[i:])
+            if i == 3:
+                w_kwds = None
+            args = Arguments(space, [1, 2], keywords, keywords_w, w_starstararg=w_kwds)
+            l = [None, None, None, None]
+            args._match_signature(None, l, Signature(["a", "b", "c"], None, "**"))
+            assert l == [1, 2, 3, {'d': 4}]
+            assert isinstance(l[-1], kwargsdict)
+
     def test_duplicate_kwds(self):
         space = DummySpace()
         excinfo = py.test.raises(OperationError, Arguments, space, [], ["a"],
@@ -546,34 +569,47 @@
     def test_missing_args(self):
         # got_nargs, nkwds, expected_nargs, has_vararg, has_kwarg,
         # defaults_w, missing_args
-        err = ArgErrCount(1, 0, 0, False, False, None, 0)
+        sig = Signature([], None, None)
+        err = ArgErrCount(1, 0, sig, None, 0)
         s = err.getmsg()
         assert s == "takes no arguments (1 given)"
-        err = ArgErrCount(0, 0, 1, False, False, [], 1)
+
+        sig = Signature(['a'], None, None)
+        err = ArgErrCount(0, 0, sig, [], 1)
         s = err.getmsg()
         assert s == "takes exactly 1 argument (0 given)"
-        err = ArgErrCount(3, 0, 2, False, False, [], 0)
+
+        sig = Signature(['a', 'b'], None, None)
+        err = ArgErrCount(3, 0, sig, [], 0)
         s = err.getmsg()
         assert s == "takes exactly 2 arguments (3 given)"
-        err = ArgErrCount(3, 0, 2, False, False, ['a'], 0)
+        err = ArgErrCount(3, 0, sig, ['a'], 0)
         s = err.getmsg()
         assert s == "takes at most 2 arguments (3 given)"
-        err = ArgErrCount(1, 0, 2, True, False, [], 1)
+
+        sig = Signature(['a', 'b'], '*', None)
+        err = ArgErrCount(1, 0, sig, [], 1)
         s = err.getmsg()
         assert s == "takes at least 2 arguments (1 given)"
-        err = ArgErrCount(0, 1, 2, True, False, ['a'], 1)
+        err = ArgErrCount(0, 1, sig, ['a'], 1)
         s = err.getmsg()
         assert s == "takes at least 1 non-keyword argument (0 given)"
-        err = ArgErrCount(2, 1, 1, False, True, [], 0)
+
+        sig = Signature(['a'], None, '**')
+        err = ArgErrCount(2, 1, sig, [], 0)
         s = err.getmsg()
         assert s == "takes exactly 1 non-keyword argument (2 given)"
-        err = ArgErrCount(0, 1, 1, False, True, [], 1)
+        err = ArgErrCount(0, 1, sig, [], 1)
         s = err.getmsg()
         assert s == "takes exactly 1 non-keyword argument (0 given)"
-        err = ArgErrCount(0, 1, 1, True, True, [], 1)
+
+        sig = Signature(['a'], '*', '**')
+        err = ArgErrCount(0, 1, sig, [], 1)
         s = err.getmsg()
         assert s == "takes at least 1 non-keyword argument (0 given)"
-        err = ArgErrCount(2, 1, 1, False, True, ['a'], 0)
+
+        sig = Signature(['a'], None, '**')
+        err = ArgErrCount(2, 1, sig, ['a'], 0)
         s = err.getmsg()
         assert s == "takes at most 1 non-keyword argument (2 given)"
 
@@ -596,11 +632,14 @@
 
     def test_unknown_keywords(self):
         space = DummySpace()
-        err = ArgErrUnknownKwds(space, 1, ['a', 'b'], [True, False], None)
+        err = ArgErrUnknownKwds(space, 1, ['a', 'b'], [0], None)
         s = err.getmsg()
         assert s == "got an unexpected keyword argument 'b'"
+        err = ArgErrUnknownKwds(space, 1, ['a', 'b'], [1], None)
+        s = err.getmsg()
+        assert s == "got an unexpected keyword argument 'a'"
         err = ArgErrUnknownKwds(space, 2, ['a', 'b', 'c'],
-                                [True, False, False], None)
+                                [0], None)
         s = err.getmsg()
         assert s == "got 2 unexpected keyword arguments"
 
@@ -610,7 +649,7 @@
                 defaultencoding = 'utf-8'
         space = DummySpaceUnicode()
         err = ArgErrUnknownKwds(space, 1, ['a', None, 'b', 'c'],
-                                [True, False, True, True],
+                                [0, 3, 2],
                                 [unichr(0x1234), u'b', u'c'])
         s = err.getmsg()
         assert s == "got an unexpected keyword argument '\xe1\x88\xb4'"
diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -96,6 +96,7 @@
     'int_add_ovf'     : (('int', 'int'), 'int'),
     'int_sub_ovf'     : (('int', 'int'), 'int'),
     'int_mul_ovf'     : (('int', 'int'), 'int'),
+    'int_force_ge_zero':(('int',), 'int'),
     'uint_add'        : (('int', 'int'), 'int'),
     'uint_sub'        : (('int', 'int'), 'int'),
     'uint_mul'        : (('int', 'int'), 'int'),
@@ -1522,6 +1523,7 @@
 
 def do_new_array(arraynum, count):
     TYPE = symbolic.Size2Type[arraynum]
+    assert count >= 0 # explode if it's not
     x = lltype.malloc(TYPE, count, zero=True)
     return cast_to_ptr(x)
 
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -4,6 +4,7 @@
 
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.jit_hooks import LOOP_RUN_CONTAINER
 from pypy.rpython.lltypesystem import lltype, llmemory, rclass
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.llinterp import LLInterpreter
@@ -33,6 +34,10 @@
         self.arg_types = arg_types
         self.count_fields_if_immut = count_fields_if_immut
         self.ffi_flags = ffi_flags
+        self._debug = False
+
+    def set_debug(self, v):
+        self._debug = True
 
     def get_arg_types(self):
         return self.arg_types
@@ -583,6 +588,9 @@
             for x in args_f:
                 llimpl.do_call_pushfloat(x)
 
+    def get_all_loop_runs(self):
+        return lltype.malloc(LOOP_RUN_CONTAINER, 0)
+
     def force(self, force_token):
         token = llmemory.cast_int_to_adr(force_token)
         frame = llimpl.get_forced_token_frame(token)
diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -659,10 +659,11 @@
 
     def _check_valid_gc(self):
         # we need the hybrid or minimark GC for rgc._make_sure_does_not_move()
-        # to work
-        if self.gcdescr.config.translation.gc not in ('hybrid', 'minimark'):
+        # to work.  Additionally, 'hybrid' is missing some stuff like
+        # jit_remember_young_pointer() for now.
+        if self.gcdescr.config.translation.gc not in ('minimark',):
             raise NotImplementedError("--gc=%s not implemented with the JIT" %
-                                      (gcdescr.config.translation.gc,))
+                                      (self.gcdescr.config.translation.gc,))
 
     def _make_gcrootmap(self):
         # to find roots in the assembler, make a GcRootMap
diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py
--- a/pypy/jit/backend/llsupport/test/test_gc.py
+++ b/pypy/jit/backend/llsupport/test/test_gc.py
@@ -296,7 +296,7 @@
 
 
 class TestFramework(object):
-    gc = 'hybrid'
+    gc = 'minimark'
 
     def setup_method(self, meth):
         class config_(object):
diff --git a/pypy/jit/backend/llsupport/test/test_rewrite.py b/pypy/jit/backend/llsupport/test/test_rewrite.py
--- a/pypy/jit/backend/llsupport/test/test_rewrite.py
+++ b/pypy/jit/backend/llsupport/test/test_rewrite.py
@@ -205,7 +205,7 @@
     def setup_method(self, meth):
         class config_(object):
             class translation(object):
-                gc = 'hybrid'
+                gc = 'minimark'
                 gcrootfinder = 'asmgcc'
                 gctransformer = 'framework'
                 gcremovetypeptr = False
diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py
--- a/pypy/jit/backend/model.py
+++ b/pypy/jit/backend/model.py
@@ -55,6 +55,21 @@
         """Called once by the front-end when the program stops."""
         pass
 
+    def get_all_loop_runs(self):
+        """ Function that will return number of times all the loops were run.
+        Requires earlier setting of set_debug(True), otherwise you won't
+        get the information.
+
+        Returns an instance of LOOP_RUN_CONTAINER from rlib.jit_hooks
+        """
+        raise NotImplementedError
+
+    def set_debug(self, value):
+        """ Enable or disable debugging info. Does nothing by default. Returns
+        the previous setting.
+        """
+        return False
+
     def compile_loop(self, inputargs, operations, looptoken, log=True, name=''):
         """Assemble the given loop.
         Should create and attach a fresh CompiledLoopToken to
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -101,7 +101,9 @@
                                       llmemory.cast_ptr_to_adr(ptrs))
 
     def set_debug(self, v):
+        r = self._debug
         self._debug = v
+        return r
 
     def setup_once(self):
         # the address of the function called by 'new'
@@ -750,7 +752,6 @@
     @specialize.argtype(1)
     def _inject_debugging_code(self, looptoken, operations, tp, number):
         if self._debug:
-            # before doing anything, let's increase a counter
             s = 0
             for op in operations:
                 s += op.getopnum()
@@ -1374,6 +1375,11 @@
     genop_cast_ptr_to_int = genop_same_as
     genop_cast_int_to_ptr = genop_same_as
 
+    def genop_int_force_ge_zero(self, op, arglocs, resloc):
+        self.mc.TEST(arglocs[0], arglocs[0])
+        self.mov(imm0, resloc)
+        self.mc.CMOVNS(arglocs[0], resloc)
+
     def genop_int_mod(self, op, arglocs, resloc):
         if IS_X86_32:
             self.mc.CDQ()
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -1188,6 +1188,12 @@
     consider_cast_ptr_to_int = consider_same_as
     consider_cast_int_to_ptr = consider_same_as
 
+    def consider_int_force_ge_zero(self, op):
+        argloc = self.make_sure_var_in_reg(op.getarg(0))
+        resloc = self.force_allocate_reg(op.result, [op.getarg(0)])
+        self.possibly_free_var(op.getarg(0))
+        self.Perform(op, [argloc], resloc)
+
     def consider_strlen(self, op):
         args = op.getarglist()
         base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args)
diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py
--- a/pypy/jit/backend/x86/regloc.py
+++ b/pypy/jit/backend/x86/regloc.py
@@ -548,6 +548,7 @@
     # Avoid XCHG because it always implies atomic semantics, which is
     # slower and does not pair well for dispatch.
     #XCHG = _binaryop('XCHG')
+    CMOVNS = _binaryop('CMOVNS')
 
     PUSH = _unaryop('PUSH')
     POP = _unaryop('POP')
diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py
--- a/pypy/jit/backend/x86/runner.py
+++ b/pypy/jit/backend/x86/runner.py
@@ -3,6 +3,7 @@
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.llinterp import LLInterpreter
 from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.jit_hooks import LOOP_RUN_CONTAINER
 from pypy.jit.codewriter import longlong
 from pypy.jit.metainterp import history, compile
 from pypy.jit.backend.x86.assembler import Assembler386
@@ -44,6 +45,9 @@
 
         self.profile_agent = profile_agent
 
+    def set_debug(self, flag):
+        return self.assembler.set_debug(flag)
+
     def setup(self):
         if self.opts is not None:
             failargs_limit = self.opts.failargs_limit
@@ -181,6 +185,14 @@
         # positions invalidated
         looptoken.compiled_loop_token.invalidate_positions = []
 
+    def get_all_loop_runs(self):
+        l = lltype.malloc(LOOP_RUN_CONTAINER,
+                          len(self.assembler.loop_run_counters))
+        for i, ll_s in enumerate(self.assembler.loop_run_counters):
+            l[i].type = ll_s.type
+            l[i].number = ll_s.number
+            l[i].counter = ll_s.i
+        return l
 
 class CPU386(AbstractX86CPU):
     backend_name = 'x86'
diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py
--- a/pypy/jit/backend/x86/rx86.py
+++ b/pypy/jit/backend/x86/rx86.py
@@ -530,6 +530,8 @@
     NOT_r = insn(rex_w, '\xF7', register(1), '\xD0')
     NOT_b = insn(rex_w, '\xF7', orbyte(2<<3), stack_bp(1))
 
+    CMOVNS_rr = insn(rex_w, '\x0F\x49', register(2, 8), register(1), '\xC0')
+
     # ------------------------------ Misc stuff ------------------------------
 
     NOP = insn('\x90')
diff --git a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py
--- a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py
+++ b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py
@@ -317,7 +317,9 @@
                 # CALL_j is actually relative, so tricky to test
                 (instrname == 'CALL' and argmodes == 'j') or
                 # SET_ir must be tested manually
-                (instrname == 'SET' and argmodes == 'ir')
+                (instrname == 'SET' and argmodes == 'ir') or
+                # asm gets CMOVNS args the wrong way
+                (instrname.startswith('CMOV'))
         )
 
 
diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py
--- a/pypy/jit/backend/x86/test/test_ztranslation.py
+++ b/pypy/jit/backend/x86/test/test_ztranslation.py
@@ -3,6 +3,7 @@
 from pypy.rlib.jit import JitDriver, unroll_parameters, set_param
 from pypy.rlib.jit import PARAMETERS, dont_look_inside
 from pypy.rlib.jit import promote
+from pypy.rlib import jit_hooks
 from pypy.jit.metainterp.jitprof import Profiler
 from pypy.jit.backend.detect_cpu import getcpuclass
 from pypy.jit.backend.test.support import CCompiledMixin
@@ -170,6 +171,23 @@
         assert 1024 <= bound <= 131072
         assert bound & (bound-1) == 0       # a power of two
 
+    def test_jit_get_stats(self):
+        driver = JitDriver(greens = [], reds = ['i'])
+        
+        def f():
+            i = 0
+            while i < 100000:
+                driver.jit_merge_point(i=i)
+                i += 1
+
+        def main():
+            jit_hooks.stats_set_debug(None, True)
+            f()
+            ll_times = jit_hooks.stats_get_loop_run_times(None)
+            return len(ll_times)
+
+        res = self.meta_interp(main, [])
+        assert res == 1
 
 class TestTranslationRemoveTypePtrX86(CCompiledMixin):
     CPUClass = getcpuclass()
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -1430,7 +1430,19 @@
 
     def do_fixed_newlist(self, op, args, arraydescr):
         v_length = self._get_initial_newlist_length(op, args)
-        return SpaceOperation('new_array', [arraydescr, v_length], op.result)
+        assert v_length.concretetype is lltype.Signed
+        ops = []
+        if isinstance(v_length, Constant):
+            if v_length.value >= 0:
+                v = v_length
+            else:
+                v = Constant(0, lltype.Signed)
+        else:
+            v = Variable('new_length')
+            v.concretetype = lltype.Signed
+            ops.append(SpaceOperation('int_force_ge_zero', [v_length], v))
+        ops.append(SpaceOperation('new_array', [arraydescr, v], op.result))
+        return ops
 
     def do_fixed_list_len(self, op, args, arraydescr):
         if args[0] in self.vable_array_vars:     # virtualizable array
diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py
--- a/pypy/jit/codewriter/policy.py
+++ b/pypy/jit/codewriter/policy.py
@@ -48,8 +48,6 @@
         mod = func.__module__ or '?'
         if mod.startswith('pypy.rpython.module.'):
             return True
-        if mod == 'pypy.translator.goal.nanos':    # more helpers
-            return True
         return False
 
     def look_inside_graph(self, graph):
diff --git a/pypy/jit/codewriter/test/test_codewriter.py b/pypy/jit/codewriter/test/test_codewriter.py
--- a/pypy/jit/codewriter/test/test_codewriter.py
+++ b/pypy/jit/codewriter/test/test_codewriter.py
@@ -221,3 +221,17 @@
     assert 'setarrayitem_raw_i' in s
     assert 'getarrayitem_raw_i' in s
     assert 'residual_call_ir_v $<* fn _ll_1_raw_free__arrayPtr>' in s
+
+def test_newlist_negativ():
+    def f(n):
+        l = [0] * n
+        return len(l)
+
+    rtyper = support.annotate(f, [-1])
+    jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
+    cw = CodeWriter(FakeCPU(rtyper), [jitdriver_sd])
+    cw.find_all_graphs(FakePolicy())
+    cw.make_jitcodes(verbose=True)
+    s = jitdriver_sd.mainjitcode.dump()
+    assert 'int_force_ge_zero' in s
+    assert 'new_array' in s
diff --git a/pypy/jit/codewriter/test/test_list.py b/pypy/jit/codewriter/test/test_list.py
--- a/pypy/jit/codewriter/test/test_list.py
+++ b/pypy/jit/codewriter/test/test_list.py
@@ -85,8 +85,11 @@
                  """new_array <ArrayDescr>, $0 -> %r0""")
     builtin_test('newlist', [Constant(5, lltype.Signed)], FIXEDLIST,
                  """new_array <ArrayDescr>, $5 -> %r0""")
+    builtin_test('newlist', [Constant(-2, lltype.Signed)], FIXEDLIST,
+                 """new_array <ArrayDescr>, $0 -> %r0""")
     builtin_test('newlist', [varoftype(lltype.Signed)], FIXEDLIST,
-                 """new_array <ArrayDescr>, %i0 -> %r0""")
+                 """int_force_ge_zero %i0 -> %i1\n"""
+                 """new_array <ArrayDescr>, %i1 -> %r0""")
     builtin_test('newlist', [Constant(5, lltype.Signed),
                              Constant(0, lltype.Signed)], FIXEDLIST,
                  """new_array <ArrayDescr>, $5 -> %r0""")
diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -477,6 +477,11 @@
     @arguments("i", "i", "i", returns="i")
     def bhimpl_int_between(a, b, c):
         return a <= b < c
+    @arguments("i", returns="i")
+    def bhimpl_int_force_ge_zero(i):
+        if i < 0:
+            return 0
+        return i
 
     @arguments("i", "i", returns="i")
     def bhimpl_uint_lt(a, b):
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -5,7 +5,7 @@
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.debug import debug_start, debug_stop, debug_print
 from pypy.rlib import rstack
-from pypy.rlib.jit import JitDebugInfo
+from pypy.rlib.jit import JitDebugInfo, Counters
 from pypy.conftest import option
 from pypy.tool.sourcetools import func_with_new_name
 
@@ -22,8 +22,7 @@
 
 def giveup():
     from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole
-    from pypy.jit.metainterp.jitprof import ABORT_BRIDGE
-    raise SwitchToBlackhole(ABORT_BRIDGE)
+    raise SwitchToBlackhole(Counters.ABORT_BRIDGE)
 
 def show_procedures(metainterp_sd, procedure=None, error=None):
     # debugging
@@ -226,6 +225,8 @@
     assert isinstance(target_token, TargetToken)
     assert loop_jitcell_token.target_tokens
     loop_jitcell_token.target_tokens.append(target_token)
+    if target_token.short_preamble:
+        metainterp_sd.logger_ops.log_short_preamble([], target_token.short_preamble)
 
     loop = partial_trace
     loop.operations = loop.operations[:-1] + part.operations
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -706,6 +706,7 @@
 
         self.virtual_state = None
         self.exported_state = None
+        self.short_preamble = None
 
     def repr_of_descr(self):
         return 'TargetToken(%d)' % compute_unique_id(self)
diff --git a/pypy/jit/metainterp/jitprof.py b/pypy/jit/metainterp/jitprof.py
--- a/pypy/jit/metainterp/jitprof.py
+++ b/pypy/jit/metainterp/jitprof.py
@@ -6,42 +6,11 @@
 from pypy.rlib.debug import debug_print, debug_start, debug_stop
 from pypy.rlib.debug import have_debug_prints
 from pypy.jit.metainterp.jitexc import JitException
+from pypy.rlib.jit import Counters
 
-counters="""
-TRACING
-BACKEND
-OPS
-RECORDED_OPS
-GUARDS
-OPT_OPS
-OPT_GUARDS
-OPT_FORCINGS
-ABORT_TOO_LONG
-ABORT_BRIDGE
-ABORT_BAD_LOOP
-ABORT_ESCAPE
-ABORT_FORCE_QUASIIMMUT
-NVIRTUALS
-NVHOLES
-NVREUSED
-TOTAL_COMPILED_LOOPS
-TOTAL_COMPILED_BRIDGES
-TOTAL_FREED_LOOPS
-TOTAL_FREED_BRIDGES
-"""
 
-counter_names = []
-
-def _setup():
-    names = counters.split()
-    for i, name in enumerate(names):
-        globals()[name] = i
-        counter_names.append(name)
-    global ncounters
-    ncounters = len(names)
-_setup()
-
-JITPROF_LINES = ncounters + 1 + 1 # one for TOTAL, 1 for calls, update if needed
+JITPROF_LINES = Counters.ncounters + 1 + 1
+# one for TOTAL, 1 for calls, update if needed
 _CPU_LINES = 4       # the last 4 lines are stored on the cpu
 
 class BaseProfiler(object):
@@ -71,9 +40,12 @@
     def count(self, kind, inc=1):
         pass
 
-    def count_ops(self, opnum, kind=OPS):
+    def count_ops(self, opnum, kind=Counters.OPS):
         pass
 
+    def get_counter(self, num):
+        return -1.0
+
 class Profiler(BaseProfiler):
     initialized = False
     timer = time.time
@@ -89,7 +61,7 @@
         self.starttime = self.timer()
         self.t1 = self.starttime
         self.times = [0, 0]
-        self.counters = [0] * (ncounters - _CPU_LINES)
+        self.counters = [0] * (Counters.ncounters - _CPU_LINES)
         self.calls = 0
         self.current = []
 
@@ -117,19 +89,30 @@
             return
         self.times[ev1] += self.t1 - t0
 
-    def start_tracing(self):   self._start(TRACING)
-    def end_tracing(self):     self._end  (TRACING)
+    def start_tracing(self):   self._start(Counters.TRACING)
+    def end_tracing(self):     self._end  (Counters.TRACING)
 
-    def start_backend(self):   self._start(BACKEND)
-    def end_backend(self):     self._end  (BACKEND)
+    def start_backend(self):   self._start(Counters.BACKEND)
+    def end_backend(self):     self._end  (Counters.BACKEND)
 
     def count(self, kind, inc=1):
         self.counters[kind] += inc        
-    
-    def count_ops(self, opnum, kind=OPS):
+
+    def get_counter(self, num):
+        if num == Counters.TOTAL_COMPILED_LOOPS:
+            return self.cpu.total_compiled_loops
+        elif num == Counters.TOTAL_COMPILED_BRIDGES:
+            return self.cpu.total_compiled_bridges
+        elif num == Counters.TOTAL_FREED_LOOPS:
+            return self.cpu.total_freed_loops
+        elif num == Counters.TOTAL_FREED_BRIDGES:
+            return self.cpu.total_freed_bridges
+        return self.counters[num]
+
+    def count_ops(self, opnum, kind=Counters.OPS):
         from pypy.jit.metainterp.resoperation import rop
         self.counters[kind] += 1
-        if opnum == rop.CALL and kind == RECORDED_OPS:# or opnum == rop.OOSEND:
+        if opnum == rop.CALL and kind == Counters.RECORDED_OPS:# or opnum == rop.OOSEND:
             self.calls += 1
 
     def print_stats(self):
@@ -142,26 +125,29 @@
         cnt = self.counters
         tim = self.times
         calls = self.calls
-        self._print_line_time("Tracing", cnt[TRACING],   tim[TRACING])
-        self._print_line_time("Backend", cnt[BACKEND],   tim[BACKEND])
+        self._print_line_time("Tracing", cnt[Counters.TRACING],
+                              tim[Counters.TRACING])
+        self._print_line_time("Backend", cnt[Counters.BACKEND],
+                              tim[Counters.BACKEND])
         line = "TOTAL:      \t\t%f" % (self.tk - self.starttime, )
         debug_print(line)
-        self._print_intline("ops", cnt[OPS])
-        self._print_intline("recorded ops", cnt[RECORDED_OPS])
+        self._print_intline("ops", cnt[Counters.OPS])
+        self._print_intline("recorded ops", cnt[Counters.RECORDED_OPS])
         self._print_intline("  calls", calls)
-        self._print_intline("guards", cnt[GUARDS])
-        self._print_intline("opt ops", cnt[OPT_OPS])
-        self._print_intline("opt guards", cnt[OPT_GUARDS])
-        self._print_intline("forcings", cnt[OPT_FORCINGS])
-        self._print_intline("abort: trace too long", cnt[ABORT_TOO_LONG])
-        self._print_intline("abort: compiling", cnt[ABORT_BRIDGE])
-        self._print_intline("abort: vable escape", cnt[ABORT_ESCAPE])
-        self._print_intline("abort: bad loop", cnt[ABORT_BAD_LOOP])
+        self._print_intline("guards", cnt[Counters.GUARDS])
+        self._print_intline("opt ops", cnt[Counters.OPT_OPS])
+        self._print_intline("opt guards", cnt[Counters.OPT_GUARDS])
+        self._print_intline("forcings", cnt[Counters.OPT_FORCINGS])
+        self._print_intline("abort: trace too long",
+                            cnt[Counters.ABORT_TOO_LONG])
+        self._print_intline("abort: compiling", cnt[Counters.ABORT_BRIDGE])
+        self._print_intline("abort: vable escape", cnt[Counters.ABORT_ESCAPE])
+        self._print_intline("abort: bad loop", cnt[Counters.ABORT_BAD_LOOP])
         self._print_intline("abort: force quasi-immut",
-                                               cnt[ABORT_FORCE_QUASIIMMUT])
-        self._print_intline("nvirtuals", cnt[NVIRTUALS])
-        self._print_intline("nvholes", cnt[NVHOLES])
-        self._print_intline("nvreused", cnt[NVREUSED])
+                            cnt[Counters.ABORT_FORCE_QUASIIMMUT])
+        self._print_intline("nvirtuals", cnt[Counters.NVIRTUALS])
+        self._print_intline("nvholes", cnt[Counters.NVHOLES])
+        self._print_intline("nvreused", cnt[Counters.NVREUSED])
         cpu = self.cpu
         if cpu is not None:   # for some tests
             self._print_intline("Total # of loops",
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/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -1,7 +1,7 @@
 import os
 
 from pypy.jit.metainterp.jitexc import JitException
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY
+from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY, LEVEL_KNOWNCLASS
 from pypy.jit.metainterp.history import ConstInt, Const
 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
 from pypy.jit.metainterp.resoperation import rop, ResOperation
@@ -128,8 +128,12 @@
             op = self._cached_fields_getfield_op[structvalue]
             if not op:
                 continue
-            if optimizer.getvalue(op.getarg(0)) in optimizer.opaque_pointers:
-                continue
+            value = optimizer.getvalue(op.getarg(0))
+            if value in optimizer.opaque_pointers:
+                if value.level < LEVEL_KNOWNCLASS:
+                    continue
+                if op.getopnum() != rop.SETFIELD_GC and op.getopnum() != rop.GETFIELD_GC:
+                    continue
             if structvalue in self._cached_fields:
                 if op.getopnum() == rop.SETFIELD_GC:
                     result = op.getarg(1)
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -401,7 +401,7 @@
             o.turned_constant(value)
 
     def forget_numberings(self, virtualbox):
-        self.metainterp_sd.profiler.count(jitprof.OPT_FORCINGS)
+        self.metainterp_sd.profiler.count(jitprof.Counters.OPT_FORCINGS)
         self.resumedata_memo.forget_numberings(virtualbox)
 
     def getinterned(self, box):
@@ -535,9 +535,9 @@
             else:
                 self.ensure_imported(value)
                 op.setarg(i, value.force_box(self))
-        self.metainterp_sd.profiler.count(jitprof.OPT_OPS)
+        self.metainterp_sd.profiler.count(jitprof.Counters.OPT_OPS)
         if op.is_guard():
-            self.metainterp_sd.profiler.count(jitprof.OPT_GUARDS)
+            self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS)
             if self.replaces_guard and op in self.replaces_guard:
                 self.replace_op(self.replaces_guard[op], op)
                 del self.replaces_guard[op]
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -241,6 +241,16 @@
             # guard_nonnull_class on this value, which is rather silly.
             # replace the original guard with a guard_value
             old_guard_op = value.last_guard
+            if old_guard_op.getopnum() != rop.GUARD_NONNULL:
+                # This is only safe if the class of the guard_value matches the
+                # class of the guard_*_class, otherwise the intermediate ops might
+                # be executed with wrong classes.
+                previous_classbox = value.get_constant_class(self.optimizer.cpu)            
+                expected_classbox = self.optimizer.cpu.ts.cls_of_box(op.getarg(1))
+                assert previous_classbox is not None
+                assert expected_classbox is not None
+                if not previous_classbox.same_constant(expected_classbox):
+                    raise InvalidLoop('A GUARD_VALUE was proven to always fail')
             op = old_guard_op.copy_and_change(rop.GUARD_VALUE,
                                       args = [old_guard_op.getarg(0), op.getarg(1)])
             self.optimizer.replaces_guard[op] = old_guard_op
@@ -251,6 +261,8 @@
             assert isinstance(descr, compile.ResumeGuardDescr)
             descr.guard_opnum = rop.GUARD_VALUE
             descr.make_a_counter_per_value(op)
+            # to be safe
+            value.last_guard = None
         constbox = op.getarg(1)
         assert isinstance(constbox, Const)
         self.optimize_guard(op, constbox)
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
@@ -431,7 +431,53 @@
         jump(i55, i81)
         """
         self.optimize_loop(ops, expected)
-        
+
+    def test_boxed_opaque_unknown_class(self):
+        ops = """
+        [p1]
+        p2 = getfield_gc(p1, descr=nextdescr) 
+        mark_opaque_ptr(p2)        
+        i3 = getfield_gc(p2, descr=otherdescr)
+        label(p1)
+        i4 = getfield_gc(p1, descr=otherdescr)
+        label(p1)
+        p5 = getfield_gc(p1, descr=nextdescr) 
+        mark_opaque_ptr(p5)        
+        i6 = getfield_gc(p5, descr=otherdescr)
+        i7 = call(i6, descr=nonwritedescr)
+        """
+        expected = """
+        [p1]
+        p2 = getfield_gc(p1, descr=nextdescr) 
+        i3 = getfield_gc(p2, descr=otherdescr)
+        label(p1)
+        i4 = getfield_gc(p1, descr=otherdescr)
+        label(p1)
+        p5 = getfield_gc(p1, descr=nextdescr) 
+        i6 = getfield_gc(p5, descr=otherdescr)
+        i7 = call(i6, descr=nonwritedescr)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_opaque_pointer_fails_to_close_loop(self):
+        ops = """
+        [p1, p11]
+        p2 = getfield_gc(p1, descr=nextdescr) 
+        guard_class(p2, ConstClass(node_vtable)) []
+        mark_opaque_ptr(p2)        
+        i3 = getfield_gc(p2, descr=otherdescr)
+        label(p1, p11)
+        p12 = getfield_gc(p1, descr=nextdescr) 
+        i13 = getfield_gc(p2, descr=otherdescr)
+        i14 = call(i13, descr=nonwritedescr)        
+        jump(p11, p1)
+        """
+        with raises(InvalidLoop):
+            self.optimize_loop(ops, ops)
+
+            
+
+
 class OptRenameStrlen(Optimization):
     def propagate_forward(self, op):
         dispatch_opt(self, op)
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -7862,6 +7862,84 @@
         """
         self.optimize_loop(ops, expected)
 
+    def test_only_strengthen_guard_if_class_matches(self):
+        ops = """
+        [p1]
+        guard_class(p1, ConstClass(node_vtable2)) []
+        guard_value(p1, ConstPtr(myptr)) []
+        jump(p1)
+        """
+        self.raises(InvalidLoop, self.optimize_loop,
+                       ops, ops)
+
+    def test_licm_boxed_opaque_getitem(self):
+        ops = """
+        [p1]
+        p2 = getfield_gc(p1, descr=nextdescr) 
+        mark_opaque_ptr(p2)        
+        guard_class(p2,  ConstClass(node_vtable)) []
+        i3 = getfield_gc(p2, descr=otherdescr)
+        i4 = call(i3, descr=nonwritedescr)
+        jump(p1)
+        """
+        expected = """
+        [p1, i3]
+        i4 = call(i3, descr=nonwritedescr)
+        jump(p1, i3)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_licm_boxed_opaque_getitem_unknown_class(self):
+        ops = """
+        [p1]
+        p2 = getfield_gc(p1, descr=nextdescr) 
+        mark_opaque_ptr(p2)        
+        i3 = getfield_gc(p2, descr=otherdescr)
+        i4 = call(i3, descr=nonwritedescr)
+        jump(p1)
+        """
+        expected = """
+        [p1, p2]
+        i3 = getfield_gc(p2, descr=otherdescr)
+        i4 = call(i3, descr=nonwritedescr)
+        jump(p1, p2)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_licm_unboxed_opaque_getitem(self):
+        ops = """
+        [p2]
+        mark_opaque_ptr(p2)        
+        guard_class(p2,  ConstClass(node_vtable)) []
+        i3 = getfield_gc(p2, descr=otherdescr)
+        i4 = call(i3, descr=nonwritedescr)
+        jump(p2)
+        """
+        expected = """
+        [p1, i3]
+        i4 = call(i3, descr=nonwritedescr)
+        jump(p1, i3)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_licm_unboxed_opaque_getitem_unknown_class(self):
+        ops = """
+        [p2]
+        mark_opaque_ptr(p2)        
+        i3 = getfield_gc(p2, descr=otherdescr)
+        i4 = call(i3, descr=nonwritedescr)
+        jump(p2)
+        """
+        expected = """
+        [p2]
+        i3 = getfield_gc(p2, descr=otherdescr) 
+        i4 = call(i3, descr=nonwritedescr)
+        jump(p2)
+        """
+        self.optimize_loop(ops, expected)
+
+
+
 class TestLLtype(OptimizeOptTest, LLtypeMixin):
     pass
 
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -120,9 +120,9 @@
                 limit = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.retrace_limit
                 if cell_token.retraced_count < limit:
                     cell_token.retraced_count += 1
-                    #debug_print('Retracing (%d/%d)' % (cell_token.retraced_count, limit))
+                    debug_print('Retracing (%d/%d)' % (cell_token.retraced_count, limit))
                 else:
-                    #debug_print("Retrace count reached, jumping to preamble")
+                    debug_print("Retrace count reached, jumping to preamble")
                     assert cell_token.target_tokens[0].virtual_state is None
                     jumpop.setdescr(cell_token.target_tokens[0])
                     self.optimizer.send_extra_operation(jumpop)
@@ -341,6 +341,12 @@
             op = self.short[i]
             newop = self.short_inliner.inline_op(op)
             self.optimizer.send_extra_operation(newop)
+            if op.result in self.short_boxes.assumed_classes:
+                classbox = self.getvalue(newop.result).get_constant_class(self.optimizer.cpu)
+                assumed_classbox = self.short_boxes.assumed_classes[op.result]
+                if not classbox or not classbox.same_constant(assumed_classbox):
+                    raise InvalidLoop('Class of opaque pointer needed in short ' +
+                                      'preamble unknown at end of loop')
             i += 1
 
         # Import boxes produced in the preamble but used in the loop
@@ -432,9 +438,13 @@
                 newargs[i] = a.clonebox()
                 boxmap[a] = newargs[i]
         inliner = Inliner(short_inputargs, newargs)
+        target_token.assumed_classes = {}
         for i in range(len(short)):
-            short[i] = inliner.inline_op(short[i])
-
+            op = short[i]
+            newop = inliner.inline_op(op)
+            if op.result and op.result in self.short_boxes.assumed_classes:
+                target_token.assumed_classes[newop.result] = self.short_boxes.assumed_classes[op.result]
+            short[i] = newop
         target_token.resume_at_jump_descr = target_token.resume_at_jump_descr.clone_if_mutable()
         inliner.inline_descr_inplace(target_token.resume_at_jump_descr)
 
@@ -588,6 +598,12 @@
                     for shop in target.short_preamble[1:]:
                         newop = inliner.inline_op(shop)
                         self.optimizer.send_extra_operation(newop)
+                        if shop.result in target.assumed_classes:
+                            classbox = self.getvalue(newop.result).get_constant_class(self.optimizer.cpu)
+                            if not classbox or not classbox.same_constant(target.assumed_classes[shop.result]):
+                                raise InvalidLoop('The class of an opaque pointer at the end ' +
+                                                  'of the bridge does not mach the class ' + 
+                                                  'it has at the start of the target loop')
                 except InvalidLoop:
                     #debug_print("Inlining failed unexpectedly",
                     #            "jumping to preamble instead")
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -288,7 +288,8 @@
 
 
 class NotVirtualStateInfo(AbstractVirtualStateInfo):
-    def __init__(self, value):
+    def __init__(self, value, is_opaque=False):
+        self.is_opaque = is_opaque
         self.known_class = value.known_class
         self.level = value.level
         if value.intbound is None:
@@ -357,6 +358,9 @@
         if self.lenbound or other.lenbound:
             raise InvalidLoop('The array length bounds does not match.')
 
+        if self.is_opaque:
+            raise InvalidLoop('Generating guards for opaque pointers is not safe')
+
         if self.level == LEVEL_KNOWNCLASS and \
            box.nonnull() and \
            self.known_class.same_constant(cpu.ts.cls_of_box(box)):
@@ -560,7 +564,8 @@
         return VirtualState([self.state(box) for box in jump_args])
 
     def make_not_virtual(self, value):
-        return NotVirtualStateInfo(value)
+        is_opaque = value in self.optimizer.opaque_pointers
+        return NotVirtualStateInfo(value, is_opaque)
 
     def make_virtual(self, known_class, fielddescrs):
         return VirtualStateInfo(known_class, fielddescrs)
@@ -585,6 +590,7 @@
         self.rename = {}
         self.optimizer = optimizer
         self.availible_boxes = availible_boxes
+        self.assumed_classes = {}
 
         if surviving_boxes is not None:
             for box in surviving_boxes:
@@ -678,6 +684,12 @@
             raise BoxNotProducable
 
     def add_potential(self, op, synthetic=False):
+        if op.result and op.result in self.optimizer.values:
+            value = self.optimizer.values[op.result]
+            if value in self.optimizer.opaque_pointers:
+                classbox = value.get_constant_class(self.optimizer.cpu)
+                if classbox:
+                    self.assumed_classes[op.result] = classbox
         if op.result not in self.potential_ops:
             self.potential_ops[op.result] = op
         else:
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -13,9 +13,7 @@
 from pypy.jit.metainterp import executor
 from pypy.jit.metainterp.logger import Logger
 from pypy.jit.metainterp.jitprof import EmptyProfiler
-from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS, ABORT_ESCAPE
-from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE, \
-                                        ABORT_FORCE_QUASIIMMUT, ABORT_BAD_LOOP
+from pypy.rlib.jit import Counters
 from pypy.jit.metainterp.jitexc import JitException, get_llexception
 from pypy.jit.metainterp.heapcache import HeapCache
 from pypy.rlib.objectmodel import specialize
@@ -224,7 +222,7 @@
                     'float_neg', 'float_abs',
                     'cast_ptr_to_int', 'cast_int_to_ptr',
                     'convert_float_bytes_to_longlong',
-                    'convert_longlong_bytes_to_float',
+                    'convert_longlong_bytes_to_float', 'int_force_ge_zero',
                     ]:
         exec py.code.Source('''
             @arguments("box")
@@ -675,7 +673,7 @@
             from pypy.jit.metainterp.quasiimmut import do_force_quasi_immutable
             do_force_quasi_immutable(self.metainterp.cpu, box.getref_base(),
                                      mutatefielddescr)
-            raise SwitchToBlackhole(ABORT_FORCE_QUASIIMMUT)
+            raise SwitchToBlackhole(Counters.ABORT_FORCE_QUASIIMMUT)
         self.generate_guard(rop.GUARD_ISNULL, mutatebox, resumepc=orgpc)
 
     def _nonstandard_virtualizable(self, pc, box):
@@ -1255,7 +1253,7 @@
         guard_op = metainterp.history.record(opnum, moreargs, None,
                                              descr=resumedescr)
         self.capture_resumedata(resumedescr, resumepc)
-        self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS)
+        self.metainterp.staticdata.profiler.count_ops(opnum, Counters.GUARDS)
         # count
         metainterp.attach_debug_info(guard_op)
         return guard_op
@@ -1776,7 +1774,7 @@
             return resbox.constbox()
         # record the operation
         profiler = self.staticdata.profiler
-        profiler.count_ops(opnum, RECORDED_OPS)
+        profiler.count_ops(opnum, Counters.RECORDED_OPS)
         self.heapcache.invalidate_caches(opnum, descr, argboxes)
         op = self.history.record(opnum, argboxes, resbox, descr)
         self.attach_debug_info(op)
@@ -1837,7 +1835,7 @@
             if greenkey_of_huge_function is not None:
                 warmrunnerstate.disable_noninlinable_function(
                     greenkey_of_huge_function)
-            raise SwitchToBlackhole(ABORT_TOO_LONG)
+            raise SwitchToBlackhole(Counters.ABORT_TOO_LONG)
 
     def _interpret(self):
         # Execute the frames forward until we raise a DoneWithThisFrame,
@@ -1921,7 +1919,7 @@
         try:
             self.prepare_resume_from_failure(key.guard_opnum, dont_change_position)
             if self.resumekey_original_loop_token is None:   # very rare case
-                raise SwitchToBlackhole(ABORT_BRIDGE)
+                raise SwitchToBlackhole(Counters.ABORT_BRIDGE)
             self.interpret()
         except SwitchToBlackhole, stb:
             self.run_blackhole_interp_to_cancel_tracing(stb)
@@ -1996,7 +1994,7 @@
                 # raises in case it works -- which is the common case
                 if self.partial_trace:
                     if  start != self.retracing_from:
-                        raise SwitchToBlackhole(ABORT_BAD_LOOP) # For now
+                        raise SwitchToBlackhole(Counters.ABORT_BAD_LOOP) # For now
                 self.compile_loop(original_boxes, live_arg_boxes, start, resumedescr)
                 # creation of the loop was cancelled!
                 self.cancel_count += 1
@@ -2005,7 +2003,7 @@
                     if memmgr:
                         if self.cancel_count > memmgr.max_unroll_loops:
                             self.staticdata.log('cancelled too many times!')
-                            raise SwitchToBlackhole(ABORT_BAD_LOOP)
+                            raise SwitchToBlackhole(Counters.ABORT_BAD_LOOP)
                 self.staticdata.log('cancelled, tracing more...')
 
         # Otherwise, no loop found so far, so continue tracing.
@@ -2299,7 +2297,8 @@
             if vinfo.tracing_after_residual_call(virtualizable):
                 # the virtualizable escaped during CALL_MAY_FORCE.
                 self.load_fields_from_virtualizable()
-                raise SwitchToBlackhole(ABORT_ESCAPE, raising_exception=True)
+                raise SwitchToBlackhole(Counters.ABORT_ESCAPE,
+                                        raising_exception=True)
                 # ^^^ we set 'raising_exception' to True because we must still
                 # have the eventual exception raised (this is normally done
                 # after the call to vable_after_residual_call()).
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -443,6 +443,7 @@
     'INT_IS_TRUE/1b',
     'INT_NEG/1',
     'INT_INVERT/1',
+    'INT_FORCE_GE_ZERO/1',
     #
     'SAME_AS/1',      # gets a Const or a Box, turns it into another Box
     'CAST_PTR_TO_INT/1',
diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py
--- a/pypy/jit/metainterp/resume.py
+++ b/pypy/jit/metainterp/resume.py
@@ -10,6 +10,7 @@
 from pypy.rpython import annlowlevel
 from pypy.rlib import rarithmetic, rstack
 from pypy.rlib.objectmodel import we_are_translated, specialize
+from pypy.rlib.objectmodel import compute_unique_id
 from pypy.rlib.debug import have_debug_prints, ll_assert
 from pypy.rlib.debug import debug_start, debug_stop, debug_print
 from pypy.jit.metainterp.optimize import InvalidLoop
@@ -254,9 +255,9 @@
         self.cached_virtuals.clear()
 
     def update_counters(self, profiler):
-        profiler.count(jitprof.NVIRTUALS, self.nvirtuals)
-        profiler.count(jitprof.NVHOLES, self.nvholes)
-        profiler.count(jitprof.NVREUSED, self.nvreused)
+        profiler.count(jitprof.Counters.NVIRTUALS, self.nvirtuals)
+        profiler.count(jitprof.Counters.NVHOLES, self.nvholes)
+        profiler.count(jitprof.Counters.NVREUSED, self.nvreused)
 
 _frame_info_placeholder = (None, 0, 0)
 
@@ -493,7 +494,7 @@
         return self.setfields(decoder, struct)
 
     def debug_prints(self):
-        debug_print("\tvirtualinfo", self.known_class.repr_rpython())
+        debug_print("\tvirtualinfo", self.known_class.repr_rpython(), " at ",  compute_unique_id(self))
         AbstractVirtualStructInfo.debug_prints(self)
 
 
@@ -509,7 +510,7 @@
         return self.setfields(decoder, struct)
 
     def debug_prints(self):
-        debug_print("\tvstructinfo", self.typedescr.repr_rpython())
+        debug_print("\tvstructinfo", self.typedescr.repr_rpython(), " at ",  compute_unique_id(self))
         AbstractVirtualStructInfo.debug_prints(self)
 
 class VArrayInfo(AbstractVirtualInfo):
@@ -539,7 +540,7 @@
         return array
 
     def debug_prints(self):
-        debug_print("\tvarrayinfo", self.arraydescr)
+        debug_print("\tvarrayinfo", self.arraydescr, " at ",  compute_unique_id(self))
         for i in self.fieldnums:
             debug_print("\t\t", str(untag(i)))
 
@@ -550,7 +551,7 @@
         self.fielddescrs = fielddescrs
 
     def debug_prints(self):
-        debug_print("\tvarraystructinfo", self.arraydescr)
+        debug_print("\tvarraystructinfo", self.arraydescr, " at ",  compute_unique_id(self))
         for i in self.fieldnums:
             debug_print("\t\t", str(untag(i)))
 
@@ -581,7 +582,7 @@
         return string
 
     def debug_prints(self):
-        debug_print("\tvstrplaininfo length", len(self.fieldnums))
+        debug_print("\tvstrplaininfo length", len(self.fieldnums), " at ",  compute_unique_id(self))
 
 
 class VStrConcatInfo(AbstractVirtualInfo):
@@ -599,7 +600,7 @@
         return string
 
     def debug_prints(self):
-        debug_print("\tvstrconcatinfo")
+        debug_print("\tvstrconcatinfo at ",  compute_unique_id(self))
         for i in self.fieldnums:
             debug_print("\t\t", str(untag(i)))
 
@@ -615,7 +616,7 @@
         return string
 
     def debug_prints(self):
-        debug_print("\tvstrsliceinfo")
+        debug_print("\tvstrsliceinfo at ",  compute_unique_id(self))
         for i in self.fieldnums:
             debug_print("\t\t", str(untag(i)))
 
@@ -636,7 +637,7 @@
         return string
 
     def debug_prints(self):
-        debug_print("\tvuniplaininfo length", len(self.fieldnums))
+        debug_print("\tvuniplaininfo length", len(self.fieldnums), " at ",  compute_unique_id(self))
 
 
 class VUniConcatInfo(AbstractVirtualInfo):
@@ -654,7 +655,7 @@
         return string
 
     def debug_prints(self):
-        debug_print("\tvuniconcatinfo")
+        debug_print("\tvuniconcatinfo at ",  compute_unique_id(self))
         for i in self.fieldnums:
             debug_print("\t\t", str(untag(i)))
 
@@ -671,7 +672,7 @@
         return string
 
     def debug_prints(self):
-        debug_print("\tvunisliceinfo")
+        debug_print("\tvunisliceinfo at ",  compute_unique_id(self))
         for i in self.fieldnums:
             debug_print("\t\t", str(untag(i)))
 
@@ -1280,7 +1281,6 @@
 
 def dump_storage(storage, liveboxes):
     "For profiling only."
-    from pypy.rlib.objectmodel import compute_unique_id
     debug_start("jit-resume")
     if have_debug_prints():
         debug_print('Log storage', compute_unique_id(storage))
@@ -1313,4 +1313,13 @@
                     debug_print('\t\t', 'None')
                 else:
                     virtual.debug_prints()
+        if storage.rd_pendingfields:
+            debug_print('\tpending setfields')
+            for i in range(len(storage.rd_pendingfields)):
+                lldescr  = storage.rd_pendingfields[i].lldescr
+                num      = storage.rd_pendingfields[i].num
+                fieldnum = storage.rd_pendingfields[i].fieldnum
+                itemindex= storage.rd_pendingfields[i].itemindex
+                debug_print("\t\t", str(lldescr), str(untag(num)), str(untag(fieldnum)), itemindex)
+
     debug_stop("jit-resume")
diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py
--- a/pypy/jit/metainterp/test/test_dict.py
+++ b/pypy/jit/metainterp/test/test_dict.py
@@ -161,6 +161,22 @@
                            'guard_no_exception': 8, 'new': 2,
                            'guard_false': 2, 'int_is_true': 2})
 
+    def test_unrolling_of_dict_iter(self):
+        driver = JitDriver(greens = [], reds = ['n'])
+        
+        def f(n):
+            while n > 0:
+                driver.jit_merge_point(n=n)
+                d = {1: 1}
+                for elem in d:
+                    n -= elem
+            return n
+
+        res = self.meta_interp(f, [10], listops=True)
+        assert res == 0
+        self.check_simple_loop({'int_sub': 1, 'int_gt': 1, 'guard_true': 1,
+                                'jump': 1})
+
 
 class TestOOtype(DictTests, OOJitMixin):
     pass
diff --git a/pypy/jit/metainterp/test/test_jitiface.py b/pypy/jit/metainterp/test/test_jitiface.py
--- a/pypy/jit/metainterp/test/test_jitiface.py
+++ b/pypy/jit/metainterp/test/test_jitiface.py
@@ -1,13 +1,15 @@
 
-from pypy.rlib.jit import JitDriver, JitHookInterface
+from pypy.rlib.jit import JitDriver, JitHookInterface, Counters
 from pypy.rlib import jit_hooks
 from pypy.jit.metainterp.test.support import LLJitMixin
 from pypy.jit.codewriter.policy import JitPolicy
-from pypy.jit.metainterp.jitprof import ABORT_FORCE_QUASIIMMUT
 from pypy.jit.metainterp.resoperation import rop
 from pypy.rpython.annlowlevel import hlstr
+from pypy.jit.metainterp.jitprof import Profiler
 
-class TestJitHookInterface(LLJitMixin):
+class JitHookInterfaceTests(object):
+    # !!!note!!! - don't subclass this from the backend. Subclass the LL
+    # class later instead
     def test_abort_quasi_immut(self):
         reasons = []
         
@@ -41,7 +43,7 @@
         assert f(100, 7) == 721
         res = self.meta_interp(f, [100, 7], policy=JitPolicy(iface))
         assert res == 721
-        assert reasons == [ABORT_FORCE_QUASIIMMUT] * 2
+        assert reasons == [Counters.ABORT_FORCE_QUASIIMMUT] * 2
 
     def test_on_compile(self):
         called = []
@@ -146,3 +148,74 @@
             assert jit_hooks.resop_getresult(op) == box5
 
         self.meta_interp(main, [])
+
+    def test_get_stats(self):
+        driver = JitDriver(greens = [], reds = ['i', 's'])
+
+        def loop(i):
+            s = 0
+            while i > 0:
+                driver.jit_merge_point(i=i, s=s)
+                if i % 2:
+                    s += 1
+                i -= 1
+                s+= 2
+            return s
+
+        def main():
+            loop(30)
+            assert jit_hooks.stats_get_counter_value(None,
+                                           Counters.TOTAL_COMPILED_LOOPS) == 1
+            assert jit_hooks.stats_get_counter_value(None,
+                                           Counters.TOTAL_COMPILED_BRIDGES) == 1
+            assert jit_hooks.stats_get_counter_value(None,
+                                                     Counters.TRACING) == 2
+            assert jit_hooks.stats_get_times_value(None, Counters.TRACING) >= 0
+
+        self.meta_interp(main, [], ProfilerClass=Profiler)
+
+class LLJitHookInterfaceTests(JitHookInterfaceTests):
+    # use this for any backend, instead of the super class
+    
+    def test_ll_get_stats(self):
+        driver = JitDriver(greens = [], reds = ['i', 's'])
+
+        def loop(i):
+            s = 0
+            while i > 0:
+                driver.jit_merge_point(i=i, s=s)
+                if i % 2:
+                    s += 1
+                i -= 1
+                s+= 2
+            return s
+
+        def main(b):
+            jit_hooks.stats_set_debug(None, b)
+            loop(30)
+            l = jit_hooks.stats_get_loop_run_times(None)
+            if b:
+                assert len(l) == 4
+                # completely specific test that would fail each time
+                # we change anything major. for now it's 4
+                # (loop, bridge, 2 entry points)
+                assert l[0].type == 'e'
+                assert l[0].number == 0
+                assert l[0].counter == 4
+                assert l[1].type == 'l'
+                assert l[1].counter == 4
+                assert l[2].type == 'l'
+                assert l[2].counter == 23
+                assert l[3].type == 'b'
+                assert l[3].number == 4
+                assert l[3].counter == 11
+            else:
+                assert len(l) == 0
+        self.meta_interp(main, [True], ProfilerClass=Profiler)
+        # this so far does not work because of the way setup_once is done,
+        # but fine, it's only about untranslated version anyway
+        #self.meta_interp(main, [False], ProfilerClass=Profiler)
+        
+
+class TestJitHookInterface(JitHookInterfaceTests, LLJitMixin):
+    pass
diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py
--- a/pypy/jit/metainterp/test/test_jitprof.py
+++ b/pypy/jit/metainterp/test/test_jitprof.py
@@ -1,9 +1,9 @@
 
 from pypy.jit.metainterp.warmspot import ll_meta_interp
-from pypy.rlib.jit import JitDriver, dont_look_inside, elidable
+from pypy.rlib.jit import JitDriver, dont_look_inside, elidable, Counters
 from pypy.jit.metainterp.test.support import LLJitMixin
 from pypy.jit.metainterp import pyjitpl
-from pypy.jit.metainterp.jitprof import *
+from pypy.jit.metainterp.jitprof import Profiler
 
 class FakeProfiler(Profiler):
     def start(self):
@@ -46,10 +46,10 @@
         assert res == 84
         profiler = pyjitpl._warmrunnerdesc.metainterp_sd.profiler
         expected = [
-            TRACING,
-            BACKEND,
-            ~ BACKEND,
-            ~ TRACING,
+            Counters.TRACING,
+            Counters.BACKEND,
+            ~ Counters.BACKEND,
+            ~ Counters.TRACING,
             ]
         assert profiler.events == expected
         assert profiler.times == [2, 1]
diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py
--- a/pypy/jit/metainterp/test/test_list.py
+++ b/pypy/jit/metainterp/test/test_list.py
@@ -251,6 +251,16 @@
         self.meta_interp(f, [10], listops=True)
         self.check_resops(new_array=0, call=0)
 
+    def test_list_mul(self):
+        def f(i):
+            l = [0] * i
+            return len(l)
+
+        r = self.interp_operations(f, [3])
+        assert r == 3
+        r = self.interp_operations(f, [-1])
+        assert r == 0
+
 class TestOOtype(ListTests, OOJitMixin):
     pass
 
diff --git a/pypy/jit/metainterp/test/test_loop.py b/pypy/jit/metainterp/test/test_loop.py
--- a/pypy/jit/metainterp/test/test_loop.py
+++ b/pypy/jit/metainterp/test/test_loop.py
@@ -871,6 +871,42 @@
         res = self.meta_interp(f, [20, 10, 1])
         assert res == f(20, 10, 1)
 
+    def test_boxed_unerased_pointers_in_short_preamble(self):
+        from pypy.rlib.rerased import new_erasing_pair
+        from pypy.rpython.lltypesystem import lltype
+        class A(object):
+            def __init__(self, val):
+                self.val = val
+            def tst(self):
+                return self.val
+
+        class Box(object):
+            def __init__(self, val):
+                self.val = val
+
+        erase_A, unerase_A = new_erasing_pair('A')
+        erase_TP, unerase_TP = new_erasing_pair('TP')
+        TP = lltype.GcArray(lltype.Signed)
+        myjitdriver = JitDriver(greens = [], reds = ['n', 'm', 'i', 'sa', 'p'])
+        def f(n, m):
+            i = sa = 0
+            p = Box(erase_A(A(7)))
+            while i < n:
+                myjitdriver.jit_merge_point(n=n, m=m, i=i, sa=sa, p=p)
+                if i < m:
+                    sa += unerase_A(p.val).tst()
+                elif i == m:
+                    a = lltype.malloc(TP, 5)
+                    a[0] = 42
+                    p = Box(erase_TP(a))
+                else:
+                    sa += unerase_TP(p.val)[0]
+                sa -= A(i).val
+                i += 1
+            return sa
+        res = self.meta_interp(f, [20, 10])
+        assert res == f(20, 10)
+
 class TestOOtype(LoopTest, OOJitMixin):
     pass
 
diff --git a/pypy/jit/metainterp/test/test_virtualstate.py b/pypy/jit/metainterp/test/test_virtualstate.py
--- a/pypy/jit/metainterp/test/test_virtualstate.py
+++ b/pypy/jit/metainterp/test/test_virtualstate.py
@@ -908,6 +908,141 @@
         """
         self.optimize_bridge(loop, bridge, expected, p5=self.myptr, p6=self.myptr2)
 
+    def test_licm_boxed_opaque_getitem(self):
+        loop = """
+        [p1]
+        p2 = getfield_gc(p1, descr=nextdescr) 
+        mark_opaque_ptr(p2)        
+        guard_class(p2,  ConstClass(node_vtable)) []
+        i3 = getfield_gc(p2, descr=otherdescr)
+        i4 = call(i3, descr=nonwritedescr)
+        jump(p1)
+        """
+        bridge = """
+        [p1]
+        guard_nonnull(p1) []
+        jump(p1)
+        """
+        expected = """
+        [p1]
+        guard_nonnull(p1) []
+        p2 = getfield_gc(p1, descr=nextdescr)
+        jump(p1)
+        """        
+        self.optimize_bridge(loop, bridge, expected, 'Preamble')
+        
+        bridge = """
+        [p1]
+        p2 = getfield_gc(p1, descr=nextdescr) 
+        guard_class(p2,  ConstClass(node_vtable2)) []
+        jump(p1)
+        """
+        expected = """
+        [p1]
+        p2 = getfield_gc(p1, descr=nextdescr) 
+        guard_class(p2,  ConstClass(node_vtable2)) []
+        jump(p1)
+        """
+        self.optimize_bridge(loop, bridge, expected, 'Preamble')
+
+        bridge = """
+        [p1]
+        p2 = getfield_gc(p1, descr=nextdescr) 
+        guard_class(p2,  ConstClass(node_vtable)) []
+        jump(p1)
+        """
+        expected = """
+        [p1]
+        p2 = getfield_gc(p1, descr=nextdescr) 
+        guard_class(p2,  ConstClass(node_vtable)) []
+        i3 = getfield_gc(p2, descr=otherdescr)
+        jump(p1, i3)
+        """
+        self.optimize_bridge(loop, bridge, expected, 'Loop')
+
+    def test_licm_unboxed_opaque_getitem(self):
+        loop = """
+        [p2]
+        mark_opaque_ptr(p2)        
+        guard_class(p2,  ConstClass(node_vtable)) []
+        i3 = getfield_gc(p2, descr=otherdescr)
+        i4 = call(i3, descr=nonwritedescr)
+        jump(p2)
+        """
+        bridge = """
+        [p1]
+        guard_nonnull(p1) []
+        jump(p1)
+        """
+        self.optimize_bridge(loop, bridge, 'RETRACE', p1=self.myptr)
+        self.optimize_bridge(loop, bridge, 'RETRACE', p1=self.myptr2)
+        
+        bridge = """
+        [p2]
+        guard_class(p2,  ConstClass(node_vtable2)) []
+        jump(p2)
+        """
+        self.optimize_bridge(loop, bridge, 'RETRACE')
+
+        bridge = """
+        [p2]
+        guard_class(p2,  ConstClass(node_vtable)) []
+        jump(p2)
+        """
+        expected = """
+        [p2]
+        guard_class(p2,  ConstClass(node_vtable)) []
+        i3 = getfield_gc(p2, descr=otherdescr)
+        jump(p2, i3)
+        """
+        self.optimize_bridge(loop, bridge, expected, 'Loop')
+
+    def test_licm_virtual_opaque_getitem(self):
+        loop = """
+        [p1]
+        p2 = getfield_gc(p1, descr=nextdescr) 
+        mark_opaque_ptr(p2)        
+        guard_class(p2,  ConstClass(node_vtable)) []
+        i3 = getfield_gc(p2, descr=otherdescr)
+        i4 = call(i3, descr=nonwritedescr)
+        p3 = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(p3, p2, descr=nextdescr)
+        jump(p3)
+        """
+        bridge = """
+        [p1]
+        p3 = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(p3, p1, descr=nextdescr)
+        jump(p3)
+        """
+        self.optimize_bridge(loop, bridge, 'RETRACE', p1=self.myptr)
+        self.optimize_bridge(loop, bridge, 'RETRACE', p1=self.myptr2)
+
+        bridge = """
+        [p1]
+        p3 = new_with_vtable(ConstClass(node_vtable))
+        guard_class(p1,  ConstClass(node_vtable2)) []
+        setfield_gc(p3, p1, descr=nextdescr)
+        jump(p3)
+        """
+        self.optimize_bridge(loop, bridge, 'RETRACE')
+
+        bridge = """
+        [p1]
+        p3 = new_with_vtable(ConstClass(node_vtable))
+        guard_class(p1,  ConstClass(node_vtable)) []
+        setfield_gc(p3, p1, descr=nextdescr)
+        jump(p3)
+        """
+        expected = """
+        [p1]
+        guard_class(p1,  ConstClass(node_vtable)) []
+        i3 = getfield_gc(p1, descr=otherdescr)
+        jump(p1, i3)
+        """
+        self.optimize_bridge(loop, bridge, expected)
+
+
 class TestLLtypeGuards(BaseTestGenerateGuards, LLtypeMixin):
     pass
 
@@ -915,6 +1050,9 @@
     pass
 
 class FakeOptimizer:
+    def __init__(self):
+        self.opaque_pointers = {}
+        self.values = {}
     def make_equal_to(*args):
         pass
     def getvalue(*args):
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -6,6 +6,7 @@
 from pypy.annotation import model as annmodel
 from pypy.rpython.llinterp import LLException
 from pypy.rpython.test.test_llinterp import get_interpreter, clear_tcache
+from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
 from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
 from pypy.objspace.flow.model import checkgraph, Link, copygraph
 from pypy.rlib.objectmodel import we_are_translated
@@ -221,7 +222,7 @@
         self.rewrite_access_helpers()
         self.codewriter.make_jitcodes(verbose=verbose)
         self.rewrite_can_enter_jits()
-        self.rewrite_set_param()
+        self.rewrite_set_param_and_get_stats()
         self.rewrite_force_virtual(vrefinfo)
         self.rewrite_force_quasi_immutable()
         self.add_finish()
@@ -632,14 +633,22 @@
             self.rewrite_access_helper(op)
 
     def rewrite_access_helper(self, op):
-        ARGS = [arg.concretetype for arg in op.args[2:]]
-        RESULT = op.result.concretetype
-        FUNCPTR = lltype.Ptr(lltype.FuncType(ARGS, RESULT))
         # make sure we make a copy of function so it no longer belongs
         # to extregistry
         func = op.args[1].value
-        func = func_with_new_name(func, func.func_name + '_compiled')
-        ptr = self.helper_func(FUNCPTR, func)
+        if func.func_name.startswith('stats_'):
+            # get special treatment since we rewrite it to a call that accepts
+            # jit driver
+            func = func_with_new_name(func, func.func_name + '_compiled')
+            def new_func(ignored, *args):
+                return func(self, *args)
+            ARGS = [lltype.Void] + [arg.concretetype for arg in op.args[3:]]
+        else:
+            ARGS = [arg.concretetype for arg in op.args[2:]]
+            new_func = func_with_new_name(func, func.func_name + '_compiled')
+        RESULT = op.result.concretetype
+        FUNCPTR = lltype.Ptr(lltype.FuncType(ARGS, RESULT))
+        ptr = self.helper_func(FUNCPTR, new_func)
         op.opname = 'direct_call'
         op.args = [Constant(ptr, FUNCPTR)] + op.args[2:]
 
@@ -859,7 +868,7 @@
             call_final_function(self.translator, finish,
                                 annhelper = self.annhelper)
 
-    def rewrite_set_param(self):
+    def rewrite_set_param_and_get_stats(self):
         from pypy.rpython.lltypesystem.rstr import STR
 
         closures = {}
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/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py
--- a/pypy/jit/tl/pypyjit_demo.py
+++ b/pypy/jit/tl/pypyjit_demo.py
@@ -1,19 +1,27 @@
 import pypyjit
 pypyjit.set_param(threshold=200)
 
+kwargs = {"z": 1}
 
-def g(*args):
-    return len(args)
+def f(*args, **kwargs):
+    result = g(1, *args, **kwargs)
+    return result + 2
 
-def f(n):
-    s = 0
-    for i in range(n):
-        l = [i, n, 2]
-        s += g(*l)
-    return s
+def g(x, y, z=2):
+    return x - y + z
+
+def main():
+    res = 0
+    i = 0
+    while i < 10000:
+        res = f(res, z=i)
+        g(1, res, **kwargs)
+        i += 1
+    return res
+
 
 try:
-    print f(301)
+    print main()
 
 except Exception, e:
     print "Exception: ", type(e)
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -43,6 +43,8 @@
         'do_what_I_mean'            : 'interp_magic.do_what_I_mean',
         'list_strategy'             : 'interp_magic.list_strategy',
         'validate_fd'               : 'interp_magic.validate_fd',
+        'newdict'                   : 'interp_dict.newdict',
+        'dictstrategy'              : 'interp_dict.dictstrategy',
     }
     if sys.platform == 'win32':
         interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp'
diff --git a/pypy/module/__pypy__/interp_dict.py b/pypy/module/__pypy__/interp_dict.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/__pypy__/interp_dict.py
@@ -0,0 +1,24 @@
+
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.interpreter.error import operationerrfmt, OperationError
+from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+
+ at unwrap_spec(type=str)
+def newdict(space, type):
+    if type == 'module':
+        return space.newdict(module=True)
+    elif type == 'instance':
+        return space.newdict(instance=True)
+    elif type == 'kwargs':
+        return space.newdict(kwargs=True)
+    elif type == 'strdict':
+        return space.newdict(strdict=True)
+    else:
+        raise operationerrfmt(space.w_TypeError, "unknown type of dict %s",
+                              type)
+
+def dictstrategy(space, w_obj):
+    if not isinstance(w_obj, W_DictMultiObject):
+        raise OperationError(space.w_TypeError,
+                             space.wrap("expecting dict object"))
+    return space.wrap('%r' % (w_obj.strategy,))
diff --git a/pypy/module/_ffi/interp_funcptr.py b/pypy/module/_ffi/interp_funcptr.py
--- a/pypy/module/_ffi/interp_funcptr.py
+++ b/pypy/module/_ffi/interp_funcptr.py
@@ -15,6 +15,51 @@
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.module._ffi.type_converter import FromAppLevelConverter, ToAppLevelConverter
 
+import os
+if os.name == 'nt':
+    def _getfunc(space, CDLL, w_name, w_argtypes, w_restype):
+        argtypes_w, argtypes, w_restype, restype = unpack_argtypes(
+            space, w_argtypes, w_restype)
+        if space.isinstance_w(w_name, space.w_str):
+            name = space.str_w(w_name)
+            try:
+                func = CDLL.cdll.getpointer(name, argtypes, restype, 
+                                            flags = CDLL.flags)
+            except KeyError:
+                raise operationerrfmt(
+                    space.w_AttributeError,
+                    "No symbol %s found in library %s", name, CDLL.name)
+
+            return W_FuncPtr(func, argtypes_w, w_restype)
+        elif space.isinstance_w(w_name, space.w_int):
+            ordinal = space.int_w(w_name)
+            try:
+                func = CDLL.cdll.getpointer_by_ordinal(
+                    ordinal, argtypes, restype, 
+                    flags = CDLL.flags)
+            except KeyError:
+                raise operationerrfmt(
+                    space.w_AttributeError,
+                    "No ordinal %d found in library %s", ordinal, CDLL.name)
+            return W_FuncPtr(func, argtypes_w, w_restype)
+        else:
+            raise OperationError(space.w_TypeError, space.wrap(
+                    'function name must be a string or integer'))
+else:    
+    @unwrap_spec(name=str)
+    def _getfunc(space, CDLL, w_name, w_argtypes, w_restype):
+        name = space.str_w(w_name)
+        argtypes_w, argtypes, w_restype, restype = unpack_argtypes(
+            space, w_argtypes, w_restype)
+        try:
+            func = CDLL.cdll.getpointer(name, argtypes, restype, 
+                                        flags = CDLL.flags)
+        except KeyError:
+            raise operationerrfmt(
+                space.w_AttributeError,
+                "No symbol %s found in library %s", name, CDLL.name)
+
+        return W_FuncPtr(func, argtypes_w, w_restype)
 
 def unwrap_ffitype(space, w_argtype, allow_void=False):
     res = w_argtype.get_ffitype()
@@ -271,19 +316,8 @@
             raise operationerrfmt(space.w_OSError, '%s: %s', self.name,
                                   e.msg or 'unspecified error')
 
-    @unwrap_spec(name=str)
-    def getfunc(self, space, name, w_argtypes, w_restype):
-        argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space,
-                                                                   w_argtypes,
-                                                                   w_restype)
-        try:
-            func = self.cdll.getpointer(name, argtypes, restype, 
-                                            flags = self.flags)
-        except KeyError:
-            raise operationerrfmt(space.w_AttributeError,
-                                  "No symbol %s found in library %s", name, self.name)
-
-        return W_FuncPtr(func, argtypes_w, w_restype)
+    def getfunc(self, space, w_name, w_argtypes, w_restype):
+        return _getfunc(space, self, w_name, w_argtypes, w_restype)
 
     @unwrap_spec(name=str)
     def getaddressindll(self, space, name):
@@ -291,8 +325,9 @@
             address_as_uint = rffi.cast(lltype.Unsigned,
                                         self.cdll.getaddressindll(name))
         except KeyError:
-            raise operationerrfmt(space.w_ValueError,
-                                  "No symbol %s found in library %s", name, self.name)
+            raise operationerrfmt(
+                space.w_ValueError,
+                "No symbol %s found in library %s", name, self.name)
         return space.wrap(address_as_uint)
 
 @unwrap_spec(name='str_or_None', mode=int)
diff --git a/pypy/module/_ffi/interp_struct.py b/pypy/module/_ffi/interp_struct.py
--- a/pypy/module/_ffi/interp_struct.py
+++ b/pypy/module/_ffi/interp_struct.py
@@ -56,8 +56,7 @@
 
 class W__StructDescr(Wrappable):
 
-    def __init__(self, space, name):
-        self.space = space
+    def __init__(self, name):
         self.w_ffitype = W_FFIType('struct %s' % name, clibffi.FFI_TYPE_NULL,
                                    w_structdescr=self)
         self.fields_w = None
@@ -69,7 +68,6 @@
             raise operationerrfmt(space.w_ValueError,
                                   "%s's fields has already been defined",
                                   self.w_ffitype.name)
-        space = self.space
         fields_w = space.fixedview(w_fields)
         # note that the fields_w returned by compute_size_and_alignement has a
         # different annotation than the original: list(W_Root) vs list(W_Field)
@@ -104,11 +102,11 @@
         return W__StructInstance(self, allocate=False, autofree=True, rawmem=rawmem)
 
     @jit.elidable_promote('0')
-    def get_type_and_offset_for_field(self, name):
+    def get_type_and_offset_for_field(self, space, name):
         try:
             w_field = self.name2w_field[name]
         except KeyError:
-            raise operationerrfmt(self.space.w_AttributeError, '%s', name)
+            raise operationerrfmt(space.w_AttributeError, '%s', name)
 
         return w_field.w_ffitype, w_field.offset
 
@@ -116,7 +114,7 @@
 
 @unwrap_spec(name=str)
 def descr_new_structdescr(space, w_type, name, w_fields=None):
-    descr = W__StructDescr(space, name)
+    descr = W__StructDescr(name)
     if w_fields is not space.w_None:
         descr.define_fields(space, w_fields)
     return descr
@@ -185,13 +183,15 @@
 
     @unwrap_spec(name=str)
     def getfield(self, space, name):
-        w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(name)
+        w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(
+            space, name)
         field_getter = GetFieldConverter(space, self.rawmem, offset)
         return field_getter.do_and_wrap(w_ffitype)
 
     @unwrap_spec(name=str)
     def setfield(self, space, name, w_value):
-        w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(name)
+        w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(
+            space, name)
         field_setter = SetFieldConverter(space, self.rawmem, offset)
         field_setter.unwrap_and_do(w_ffitype, w_value)
 
diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py
--- a/pypy/module/_ffi/test/test_funcptr.py
+++ b/pypy/module/_ffi/test/test_funcptr.py
@@ -627,4 +627,17 @@
                             types.void, FUNCFLAG_STDCALL)
         sleep(10)
 
- 
+    def test_by_ordinal(self):
+        """
+            int DLLEXPORT AAA_first_ordinal_function()
+            {
+                return 42;
+            }
+        """
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import CDLL, types
+        libfoo = CDLL(self.libfoo_name)
+        f_name = libfoo.getfunc('AAA_first_ordinal_function', [], types.sint)
+        f_ordinal = libfoo.getfunc(1, [], types.sint)
+        assert f_name.getaddr() == f_ordinal.getaddr()
diff --git a/pypy/module/_ffi/test/test_ztranslation.py b/pypy/module/_ffi/test/test_ztranslation.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/test/test_ztranslation.py
@@ -0,0 +1,4 @@
+from pypy.objspace.fake.checkmodule import checkmodule
+
+def test__ffi_translates():
+    checkmodule('_ffi', '_rawffi')
diff --git a/pypy/module/_sre/interp_sre.py b/pypy/module/_sre/interp_sre.py
--- a/pypy/module/_sre/interp_sre.py
+++ b/pypy/module/_sre/interp_sre.py
@@ -7,7 +7,7 @@
 from pypy.interpreter.error import OperationError
 from pypy.rlib.rarithmetic import intmask
 from pypy.tool.pairtype import extendabletype
-
+from pypy.rlib import jit
 
 # ____________________________________________________________
 #
@@ -344,6 +344,7 @@
         raise OperationError(space.w_TypeError,
                              space.wrap("cannot copy this match object"))
 
+    @jit.look_inside_iff(lambda self, args_w: jit.isconstant(len(args_w)))
     def group_w(self, args_w):
         space = self.space
         ctx = self.ctx
diff --git a/pypy/module/_ssl/__init__.py b/pypy/module/_ssl/__init__.py
--- a/pypy/module/_ssl/__init__.py
+++ b/pypy/module/_ssl/__init__.py
@@ -31,5 +31,6 @@
     def startup(self, space):
         from pypy.rlib.ropenssl import init_ssl
         init_ssl()
-        from pypy.module._ssl.interp_ssl import setup_ssl_threads
-        setup_ssl_threads()
+        if space.config.objspace.usemodules.thread:
+            from pypy.module._ssl.thread_lock import setup_ssl_threads
+            setup_ssl_threads()
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -789,7 +789,11 @@
 def _ssl_seterror(space, ss, ret):
     assert ret <= 0
 
-    if ss and ss.ssl:
+    if ss is None:
+        errval = libssl_ERR_peek_last_error()
+        errstr = rffi.charp2str(libssl_ERR_error_string(errval, None))
+        return ssl_error(space, errstr, errval)
+    elif ss.ssl:
         err = libssl_SSL_get_error(ss.ssl, ret)
     else:
         err = SSL_ERROR_SSL
@@ -880,38 +884,3 @@
             libssl_X509_free(x)
     finally:
         libssl_BIO_free(cert)
-
-# this function is needed to perform locking on shared data
-# structures. (Note that OpenSSL uses a number of global data
-# structures that will be implicitly shared whenever multiple threads
-# use OpenSSL.) Multi-threaded applications will crash at random if
-# it is not set.
-#
-# locking_function() must be able to handle up to CRYPTO_num_locks()
-# different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
-# releases it otherwise.
-#
-# filename and line are the file number of the function setting the
-# lock. They can be useful for debugging.
-_ssl_locks = []
-
-def _ssl_thread_locking_function(mode, n, filename, line):
-    n = intmask(n)
-    if n < 0 or n >= len(_ssl_locks):
-        return
-
-    if intmask(mode) & CRYPTO_LOCK:
-        _ssl_locks[n].acquire(True)
-    else:
-        _ssl_locks[n].release()
-
-def _ssl_thread_id_function():
-    from pypy.module.thread import ll_thread
-    return rffi.cast(rffi.LONG, ll_thread.get_ident())
-
-def setup_ssl_threads():
-    from pypy.module.thread import ll_thread
-    for i in range(libssl_CRYPTO_num_locks()):
-        _ssl_locks.append(ll_thread.allocate_lock())
-    libssl_CRYPTO_set_locking_callback(_ssl_thread_locking_function)
-    libssl_CRYPTO_set_id_callback(_ssl_thread_id_function)
diff --git a/pypy/module/_ssl/test/test_ztranslation.py b/pypy/module/_ssl/test/test_ztranslation.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ssl/test/test_ztranslation.py
@@ -0,0 +1,4 @@
+from pypy.objspace.fake.checkmodule import checkmodule
+
+def test__ffi_translates():
+    checkmodule('_ssl')
diff --git a/pypy/module/_ssl/thread_lock.py b/pypy/module/_ssl/thread_lock.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ssl/thread_lock.py
@@ -0,0 +1,80 @@
+from pypy.rlib.ropenssl import *
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+
+# CRYPTO_set_locking_callback:
+#
+# this function is needed to perform locking on shared data
+# structures. (Note that OpenSSL uses a number of global data
+# structures that will be implicitly shared whenever multiple threads
+# use OpenSSL.) Multi-threaded applications will crash at random if
+# it is not set.
+#
+# locking_function() must be able to handle up to CRYPTO_num_locks()
+# different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
+# releases it otherwise.
+#
+# filename and line are the file number of the function setting the
+# lock. They can be useful for debugging.
+
+
+# This logic is moved to C code so that the callbacks can be invoked
+# without caring about the GIL.
+
+separate_module_source = """
+
+#include <openssl/crypto.h>
+
+static unsigned int _ssl_locks_count = 0;
+static struct RPyOpaque_ThreadLock *_ssl_locks;
+
+static unsigned long _ssl_thread_id_function(void) {
+    return RPyThreadGetIdent();
+}
+
+static void _ssl_thread_locking_function(int mode, int n, const char *file,
+                                         int line) {
+    if ((_ssl_locks == NULL) ||
+        (n < 0) || ((unsigned)n >= _ssl_locks_count))
+        return;
+
+    if (mode & CRYPTO_LOCK) {
+        RPyThreadAcquireLock(_ssl_locks + n, 1);
+    } else {
+        RPyThreadReleaseLock(_ssl_locks + n);
+    }
+}
+
+int _PyPy_SSL_SetupThreads(void)
+{
+    unsigned int i;
+    _ssl_locks_count = CRYPTO_num_locks();
+    _ssl_locks = calloc(_ssl_locks_count, sizeof(struct RPyOpaque_ThreadLock));
+    if (_ssl_locks == NULL)
+        return 0;
+    for (i=0; i<_ssl_locks_count; i++) {
+        if (RPyThreadLockInit(_ssl_locks + i) == 0)
+            return 0;
+    }
+    CRYPTO_set_locking_callback(_ssl_thread_locking_function);
+    CRYPTO_set_id_callback(_ssl_thread_id_function);
+    return 1;
+}
+"""
+
+
+eci = ExternalCompilationInfo(
+    separate_module_sources=[separate_module_source],
+    post_include_bits=[
+        "int _PyPy_SSL_SetupThreads(void);"],
+    export_symbols=['_PyPy_SSL_SetupThreads'],
+)
+
+_PyPy_SSL_SetupThreads = rffi.llexternal('_PyPy_SSL_SetupThreads',
+                                         [], rffi.INT,
+                                         compilation_info=eci)
+
+def setup_ssl_threads():
+    result = _PyPy_SSL_SetupThreads()
+    if rffi.cast(lltype.Signed, result) == 0:
+        raise MemoryError
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -9,7 +9,7 @@
 from pypy.objspace.std.multimethod import FailedToImplement
 from pypy.objspace.std.stdtypedef import SMM, StdTypeDef
 from pypy.objspace.std.register_all import register_all
-from pypy.rlib.rarithmetic import ovfcheck
+from pypy.rlib.rarithmetic import ovfcheck, widen
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.objectmodel import specialize, keepalive_until_here
 from pypy.rpython.lltypesystem import lltype, rffi
@@ -164,6 +164,8 @@
         data[index] = char
         array._charbuf_stop()
 
+    def get_raw_address(self):
+        return self.array._charbuf_start()
 
 def make_array(mytype):
     W_ArrayBase = globals()['W_ArrayBase']
@@ -225,20 +227,29 @@
             # length
             self.setlen(0)
 
-        def setlen(self, size):
+        def setlen(self, size, zero=False, overallocate=True):
             if size > 0:
                 if size > self.allocated or size < self.allocated / 2:
-                    if size < 9:
-                        some = 3
+                    if overallocate:
+                        if size < 9:
+                            some = 3
+                        else:
+                            some = 6
+                        some += size >> 3
                     else:
-                        some = 6
-                    some += size >> 3
+                        some = 0
                     self.allocated = size + some
-                    new_buffer = lltype.malloc(mytype.arraytype,
-                                               self.allocated, flavor='raw',
-                                               add_memory_pressure=True)
-                    for i in range(min(size, self.len)):
-                        new_buffer[i] = self.buffer[i]
+                    if zero:
+                        new_buffer = lltype.malloc(mytype.arraytype,
+                                                   self.allocated, flavor='raw',
+                                                   add_memory_pressure=True,
+                                                   zero=True)
+                    else:
+                        new_buffer = lltype.malloc(mytype.arraytype,
+                                                   self.allocated, flavor='raw',
+                                                   add_memory_pressure=True)
+                        for i in range(min(size, self.len)):
+                            new_buffer[i] = self.buffer[i]
                 else:
                     self.len = size
                     return
@@ -344,7 +355,7 @@
     def getitem__Array_Slice(space, self, w_slice):
         start, stop, step, size = space.decode_index4(w_slice, self.len)
         w_a = mytype.w_class(self.space)
-        w_a.setlen(size)
+        w_a.setlen(size, overallocate=False)
         assert step != 0
         j = 0
         for i in range(start, stop, step):
@@ -366,26 +377,18 @@
     def setitem__Array_Slice_Array(space, self, w_idx, w_item):
         start, stop, step, size = self.space.decode_index4(w_idx, self.len)
         assert step != 0
-        if w_item.len != size:
+        if w_item.len != size or self is w_item:
+            # XXX this is a giant slow hack
             w_lst = array_tolist__Array(space, self)
             w_item = space.call_method(w_item, 'tolist')
             space.setitem(w_lst, w_idx, w_item)
             self.setlen(0)
             self.fromsequence(w_lst)
         else:
-            if self is w_item:
-                with lltype.scoped_alloc(mytype.arraytype, self.allocated) as new_buffer:
-                    for i in range(self.len):
-                        new_buffer[i] = w_item.buffer[i]
-                    j = 0
-                    for i in range(start, stop, step):
-                        self.buffer[i] = new_buffer[j]
-                        j += 1
-            else:
-                j = 0
-                for i in range(start, stop, step):
-                    self.buffer[i] = w_item.buffer[j]
-                    j += 1
+            j = 0
+            for i in range(start, stop, step):
+                self.buffer[i] = w_item.buffer[j]
+                j += 1
 
     def setslice__Array_ANY_ANY_ANY(space, self, w_i, w_j, w_x):
         space.setitem(self, space.newslice(w_i, w_j, space.w_None), w_x)
@@ -457,6 +460,7 @@
         self.buffer[i] = val
 
     def delitem__Array_ANY(space, self, w_idx):
+        # XXX this is a giant slow hack
         w_lst = array_tolist__Array(space, self)
         space.delitem(w_lst, w_idx)
         self.setlen(0)
@@ -469,7 +473,7 @@
 
     def add__Array_Array(space, self, other):
         a = mytype.w_class(space)
-        a.setlen(self.len + other.len)
+        a.setlen(self.len + other.len, overallocate=False)
         for i in range(self.len):
             a.buffer[i] = self.buffer[i]
         for i in range(other.len):
@@ -485,46 +489,58 @@
         return self
 
     def mul__Array_ANY(space, self, w_repeat):
+        return _mul_helper(space, self, w_repeat, False)
+
+    def mul__ANY_Array(space, w_repeat, self):
+        return _mul_helper(space, self, w_repeat, False)
+
+    def inplace_mul__Array_ANY(space, self, w_repeat):
+        return _mul_helper(space, self, w_repeat, True)
+
+    def _mul_helper(space, self, w_repeat, is_inplace):
         try:
             repeat = space.getindex_w(w_repeat, space.w_OverflowError)
         except OperationError, e:
             if e.match(space, space.w_TypeError):
                 raise FailedToImplement
             raise
-        a = mytype.w_class(space)
         repeat = max(repeat, 0)
         try:
             newlen = ovfcheck(self.len * repeat)
         except OverflowError:
             raise MemoryError
-        a.setlen(newlen)
-        for r in range(repeat):
-            for i in range(self.len):
-                a.buffer[r * self.len + i] = self.buffer[i]
+        oldlen = self.len
+        if is_inplace:
+            a = self
+            start = 1
+        else:
+            a = mytype.w_class(space)
+            start = 0
+        # <a performance hack>
+        if oldlen == 1:
+            if mytype.unwrap == 'str_w' or mytype.unwrap == 'unicode_w':
+                zero = not ord(self.buffer[0])
+            elif mytype.unwrap == 'int_w' or mytype.unwrap == 'bigint_w':
+                zero = not widen(self.buffer[0])
+            #elif mytype.unwrap == 'float_w':
+            #    value = ...float(self.buffer[0])  xxx handle the case of -0.0
+            else:
+                zero = False
+            if zero:
+                a.setlen(newlen, zero=True, overallocate=False)
+                return a
+            a.setlen(newlen, overallocate=False)
+            item = self.buffer[0]
+            for r in range(start, repeat):
+                a.buffer[r] = item
+            return a
+        # </a performance hack>
+        a.setlen(newlen, overallocate=False)
+        for r in range(start, repeat):
+            for i in range(oldlen):
+                a.buffer[r * oldlen + i] = self.buffer[i]
         return a
 
-    def mul__ANY_Array(space, w_repeat, self):
-        return mul__Array_ANY(space, self, w_repeat)
-
-    def inplace_mul__Array_ANY(space, self, w_repeat):
-        try:
-            repeat = space.getindex_w(w_repeat, space.w_OverflowError)
-        except OperationError, e:
-            if e.match(space, space.w_TypeError):
-                raise FailedToImplement
-            raise
-        oldlen = self.len
-        repeat = max(repeat, 0)
-        try:
-            newlen = ovfcheck(self.len * repeat)
-        except OverflowError:
-            raise MemoryError
-        self.setlen(newlen)
-        for r in range(1, repeat):
-            for i in range(oldlen):
-                self.buffer[r * oldlen + i] = self.buffer[i]
-        return self
-
     # Convertions
 
     def array_tolist__Array(space, self):
@@ -600,6 +616,7 @@
     # Compare methods
     @specialize.arg(3)
     def _cmp_impl(space, self, other, space_fn):
+        # XXX this is a giant slow hack
         w_lst1 = array_tolist__Array(space, self)
         w_lst2 = space.call_method(other, 'tolist')
         return space_fn(w_lst1, w_lst2)
@@ -646,7 +663,7 @@
 
     def array_copy__Array(space, self):
         w_a = mytype.w_class(self.space)
-        w_a.setlen(self.len)
+        w_a.setlen(self.len, overallocate=False)
         rffi.c_memcpy(
             rffi.cast(rffi.VOIDP, w_a.buffer),
             rffi.cast(rffi.VOIDP, self.buffer),
diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -890,6 +890,54 @@
         a[::-1] = a
         assert a == self.array('b', [3, 2, 1, 0])
 
+    def test_array_multiply(self):
+        a = self.array('b', [0])
+        b = a * 13
+        assert b[12] == 0
+        b = 13 * a
+        assert b[12] == 0
+        a *= 13
+        assert a[12] == 0
+        a = self.array('b', [1])
+        b = a * 13
+        assert b[12] == 1
+        b = 13 * a
+        assert b[12] == 1
+        a *= 13
+        assert a[12] == 1
+        a = self.array('i', [0])
+        b = a * 13
+        assert b[12] == 0
+        b = 13 * a
+        assert b[12] == 0
+        a *= 13
+        assert a[12] == 0
+        a = self.array('i', [1])
+        b = a * 13
+        assert b[12] == 1
+        b = 13 * a
+        assert b[12] == 1
+        a *= 13
+        assert a[12] == 1
+        a = self.array('i', [0, 0])
+        b = a * 13
+        assert len(b) == 26
+        assert b[22] == 0
+        b = 13 * a
+        assert len(b) == 26
+        assert b[22] == 0
+        a *= 13
+        assert a[22] == 0
+        assert len(a) == 26
+        a = self.array('f', [-0.0])
+        b = a * 13
+        assert len(b) == 13
+        assert str(b[12]) == "-0.0"
+        a = self.array('d', [-0.0])
+        b = a * 13
+        assert len(b) == 13
+        assert str(b[12]) == "-0.0"
+
 
 class AppTestArrayBuiltinShortcut(AppTestArray):
     OPTIONS = {'objspace.std.builtinshortcut': True}
diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py
--- a/pypy/module/cStringIO/interp_stringio.py
+++ b/pypy/module/cStringIO/interp_stringio.py
@@ -221,7 +221,8 @@
 }
 
 W_InputType.typedef = TypeDef(
-    "cStringIO.StringI",
+    "StringI",
+    __module__   = "cStringIO",
     __doc__      = "Simple type for treating strings as input file streams",
     closed       = GetSetProperty(descr_closed, cls=W_InputType),
     softspace    = GetSetProperty(descr_softspace,
@@ -232,7 +233,8 @@
     )
 
 W_OutputType.typedef = TypeDef(
-    "cStringIO.StringO",
+    "StringO",
+    __module__   = "cStringIO",
     __doc__      = "Simple type for output to strings.",
     truncate     = interp2app(W_OutputType.descr_truncate),
     write        = interp2app(W_OutputType.descr_write),
diff --git a/pypy/module/cppyy/__init__.py b/pypy/module/cppyy/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/__init__.py
@@ -0,0 +1,22 @@
+from pypy.interpreter.mixedmodule import MixedModule
+
+class Module(MixedModule):
+    """    """
+
+    interpleveldefs = {
+        '_load_dictionary'       : 'interp_cppyy.load_dictionary',
+        '_resolve_name'          : 'interp_cppyy.resolve_name',
+        '_scope_byname'          : 'interp_cppyy.scope_byname',
+        '_template_byname'       : 'interp_cppyy.template_byname',
+        '_set_class_generator'   : 'interp_cppyy.set_class_generator',
+        '_register_class'        : 'interp_cppyy.register_class',
+        'CPPInstance'            : 'interp_cppyy.W_CPPInstance',
+        'addressof'              : 'interp_cppyy.addressof',
+        'bind_object'            : 'interp_cppyy.bind_object',
+    }
+
+    appleveldefs = {
+        'gbl'                    : 'pythonify.gbl',
+        'load_reflection_info'   : 'pythonify.load_reflection_info',
+        'add_pythonization'      : 'pythonify.add_pythonization',
+    }
diff --git a/pypy/module/cppyy/bench/Makefile b/pypy/module/cppyy/bench/Makefile
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/Makefile
@@ -0,0 +1,29 @@
+all: bench02Dict_reflex.so
+
+ROOTSYS := ${ROOTSYS}
+
+ifeq ($(ROOTSYS),)
+  genreflex=genreflex
+  cppflags=
+else
+  genreflex=$(ROOTSYS)/bin/genreflex
+  cppflags=-I$(ROOTSYS)/include -L$(ROOTSYS)/lib
+endif
+
+PLATFORM := $(shell uname -s)
+ifeq ($(PLATFORM),Darwin)
+  cppflags+=-dynamiclib -single_module -arch x86_64
+endif
+
+ifeq ($(shell $(genreflex) --help | grep -- --with-methptrgetter),)
+  genreflexflags=
+  cppflags2=-O3 -fPIC
+else
+  genreflexflags=--with-methptrgetter
+  cppflags2=-Wno-pmf-conversions -O3 -fPIC
+endif
+
+
+bench02Dict_reflex.so: bench02.h bench02.cxx bench02.xml
+	$(genreflex) bench02.h $(genreflexflags) --selection=bench02.xml -I$(ROOTSYS)/include
+	g++ -o $@ bench02.cxx bench02_rflx.cpp -I$(ROOTSYS)/include -shared -lReflex -lHistPainter `root-config --libs` $(cppflags) $(cppflags2)
diff --git a/pypy/module/cppyy/bench/bench02.cxx b/pypy/module/cppyy/bench/bench02.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/bench02.cxx
@@ -0,0 +1,79 @@
+#include "bench02.h"
+
+#include "TROOT.h"
+#include "TApplication.h"
+#include "TDirectory.h"
+#include "TInterpreter.h"
+#include "TSystem.h"
+#include "TBenchmark.h"
+#include "TStyle.h"
+#include "TError.h"
+#include "Getline.h"
+#include "TVirtualX.h"
+
+#include "Api.h"
+
+#include <iostream>
+
+TClass *TClass::GetClass(const char*, Bool_t, Bool_t) {
+    static TClass* dummy = new TClass("__dummy__", kTRUE);
+    return dummy;  // is deleted by gROOT at shutdown
+}
+
+class TTestApplication : public TApplication {
+public:
+    TTestApplication(
+        const char* acn, Int_t* argc, char** argv, Bool_t bLoadLibs = kTRUE);
+    virtual ~TTestApplication();
+};
+
+TTestApplication::TTestApplication(
+        const char* acn, int* argc, char** argv, bool do_load) : TApplication(acn, argc, argv) {
+    if (do_load) {
+        // follow TRint to minimize differences with CINT
+        ProcessLine("#include <iostream>", kTRUE);
+        ProcessLine("#include <_string>",  kTRUE); // for std::string iostream.
+        ProcessLine("#include <vector>",   kTRUE); // needed because they're used within the
+        ProcessLine("#include <pair>",     kTRUE); //  core ROOT dicts and CINT won't be able
+                                                   //  to properly unload these files
+    }
+
+    // save current interpreter context
+    gInterpreter->SaveContext();
+    gInterpreter->SaveGlobalsContext();
+
+    // prevent crashes on accessing history
+    Gl_histinit((char*)"-");
+
+    // prevent ROOT from exiting python
+    SetReturnFromRun(kTRUE);
+}
+
+TTestApplication::~TTestApplication() {}
+
+static const char* appname = "pypy-cppyy";
+
+Bench02RootApp::Bench02RootApp() {
+    gROOT->SetBatch(kTRUE);
+    if (!gApplication) {
+        int argc = 1;
+        char* argv[1]; argv[0] = (char*)appname;
+        gApplication = new TTestApplication(appname, &argc, argv, kFALSE);
+    }
+}
+
+Bench02RootApp::~Bench02RootApp() {
+    // TODO: ROOT globals cleanup ... (?)
+}
+
+void Bench02RootApp::report() {
+    std::cout << "gROOT is: " << gROOT << std::endl;
+    std::cout << "gApplication is: " << gApplication << std::endl;
+}
+
+void Bench02RootApp::close_file(TFile* f) {
+    std::cout << "closing file " << f->GetName() << " ... " << std::endl;
+    f->Write();
+    f->Close();
+    std::cout << "... file closed" << std::endl;
+}
diff --git a/pypy/module/cppyy/bench/bench02.h b/pypy/module/cppyy/bench/bench02.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/bench02.h
@@ -0,0 +1,72 @@
+#include "TString.h"
+
+#include "TCanvas.h"
+#include "TFile.h"
+#include "TProfile.h"
+#include "TNtuple.h"
+#include "TH1F.h"
+#include "TH2F.h"
+#include "TRandom.h"
+#include "TRandom3.h"
+
+#include "TROOT.h"
+#include "TApplication.h"
+#include "TSystem.h"
+
+#include "TArchiveFile.h"
+#include "TBasket.h"
+#include "TBenchmark.h"
+#include "TBox.h"
+#include "TBranchRef.h"
+#include "TBrowser.h"
+#include "TClassGenerator.h"
+#include "TClassRef.h"
+#include "TClassStreamer.h"
+#include "TContextMenu.h"
+#include "TEntryList.h"
+#include "TEventList.h"
+#include "TF1.h"
+#include "TFileCacheRead.h"
+#include "TFileCacheWrite.h"
+#include "TFileMergeInfo.h"
+#include "TFitResult.h"
+#include "TFolder.h"
+//#include "TFormulaPrimitive.h"
+#include "TFunction.h"
+#include "TFrame.h"
+#include "TGlobal.h"
+#include "THashList.h"
+#include "TInetAddress.h"
+#include "TInterpreter.h"
+#include "TKey.h"
+#include "TLegend.h"
+#include "TMethodCall.h"
+#include "TPluginManager.h"
+#include "TProcessUUID.h"
+#include "TSchemaRuleSet.h"
+#include "TStyle.h"
+#include "TSysEvtHandler.h"
+#include "TTimer.h"
+#include "TView.h"
+//#include "TVirtualCollectionProxy.h"
+#include "TVirtualFFT.h"
+#include "TVirtualHistPainter.h"
+#include "TVirtualIndex.h"
+#include "TVirtualIsAProxy.h"
+#include "TVirtualPadPainter.h"
+#include "TVirtualRefProxy.h"
+#include "TVirtualStreamerInfo.h"
+#include "TVirtualViewer3D.h"
+
+#include <typeinfo>
+#include <ostream>
+
+
+class Bench02RootApp {
+public:
+   Bench02RootApp();
+   ~Bench02RootApp();
+
+   void report();
+   void close_file(TFile* f);
+};
diff --git a/pypy/module/cppyy/bench/bench02.xml b/pypy/module/cppyy/bench/bench02.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/bench02.xml
@@ -0,0 +1,41 @@
+<lcgdict>
+
+  <selection>
+
+     <!-- ROOT classes -->
+     <class pattern="T[A-Z]*" />
+     <class pattern="ROOT::T[A-Z]*" />
+     <class pattern="ROOT::Fit::*" />
+
+     <!-- ROOT globals -->
+     <variable name="gROOT" />
+     <variable name="gSystem" />
+     <variable name="gRandom" />
+
+     <!-- STL classes actually used -->
+     <class name="std::string" />
+     <class name="std::ostream" />
+     <class name="std::type_info" />
+     <class pattern="std::vector<*>" />
+     <class pattern="std::_Vector_base<*>" />
+
+     <!-- helper -->
+     <class name="Bench02RootApp" />
+
+  </selection>
+
+  <exclusion>
+
+     <struct pattern="TString::*" />
+     <class name="TString" >
+         <field name="fRep" transient="true"/>
+     </class>
+
+     <class name="TUUID::uuid_time_t" />
+
+     <class name="TClass::TNameMapNode" />
+     <class name="TFileOpenHandle" />
+
+  </exclusion>
+
+</lcgdict>
diff --git a/pypy/module/cppyy/bench/hsimple.C b/pypy/module/cppyy/bench/hsimple.C
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/hsimple.C
@@ -0,0 +1,109 @@
+#include <TFile.h>
+#include <TNtuple.h>
+#include <TH2.h>
+#include <TProfile.h>
+#include <TCanvas.h>
+#include <TFrame.h>
+#include <TROOT.h>
+#include <TSystem.h>
+#include <TRandom3.h>
+#include <TBenchmark.h>
+#include <TInterpreter.h>
+
+TFile *hsimple(Int_t get=0)
+{
+//  This program creates :
+//    - a one dimensional histogram
+//    - a two dimensional histogram
+//    - a profile histogram
+//    - a memory-resident ntuple
+//
+//  These objects are filled with some random numbers and saved on a file.
+//  If get=1 the macro returns a pointer to the TFile of "hsimple.root"
+//          if this file exists, otherwise it is created.
+//  The file "hsimple.root" is created in $ROOTSYS/tutorials if the caller has
+//  write access to this directory, otherwise the file is created in $PWD
+
+   TString filename = "hsimple.root";
+   TString dir = gSystem->UnixPathName(gInterpreter->GetCurrentMacroName());
+   dir.ReplaceAll("hsimple.C","");
+   dir.ReplaceAll("/./","/");
+   TFile *hfile = 0;
+   if (get) {
+      // if the argument get =1 return the file "hsimple.root"
+      // if the file does not exist, it is created
+      TString fullPath = dir+"hsimple.root";
+      if (!gSystem->AccessPathName(fullPath,kFileExists)) {
+	 hfile = TFile::Open(fullPath); //in $ROOTSYS/tutorials
+         if (hfile) return hfile;
+      }
+      //otherwise try $PWD/hsimple.root
+      if (!gSystem->AccessPathName("hsimple.root",kFileExists)) {
+         hfile = TFile::Open("hsimple.root"); //in current dir
+         if (hfile) return hfile;
+      }
+   }
+   //no hsimple.root file found. Must generate it !
+   //generate hsimple.root in $ROOTSYS/tutorials if we have write access
+   if (!gSystem->AccessPathName(dir,kWritePermission)) {
+      filename = dir+"hsimple.root";
+   } else if (!gSystem->AccessPathName(".",kWritePermission)) {
+      //otherwise generate hsimple.root in the current directory
+   } else {
+      printf("you must run the script in a directory with write access\n");
+      return 0;
+   }
+   hfile = (TFile*)gROOT->FindObject(filename); if (hfile) hfile->Close();
+   hfile = new TFile(filename,"RECREATE","Demo ROOT file with histograms");
+
+   // Create some histograms, a profile histogram and an ntuple
+   TH1F *hpx = new TH1F("hpx","This is the px distribution",100,-4,4);
+   hpx->SetFillColor(48);
+   TH2F *hpxpy = new TH2F("hpxpy","py vs px",40,-4,4,40,-4,4);
+   TProfile *hprof = new TProfile("hprof","Profile of pz versus px",100,-4,4,0,20);
+   TNtuple *ntuple = new TNtuple("ntuple","Demo ntuple","px:py:pz:random:i");
+
+   gBenchmark->Start("hsimple");
+  
+   // Create a new canvas.
+   TCanvas *c1 = new TCanvas("c1","Dynamic Filling Example",200,10,700,500);
+   c1->SetFillColor(42);
+   c1->GetFrame()->SetFillColor(21);
+   c1->GetFrame()->SetBorderSize(6);
+   c1->GetFrame()->SetBorderMode(-1);
+
+
+   // Fill histograms randomly
+   TRandom3 random;
+   Float_t px, py, pz;
+   const Int_t kUPDATE = 1000;
+   for (Int_t i = 0; i < 50000; i++) {
+   //      random.Rannor(px,py);
+      px = random.Gaus(0, 1);
+      py = random.Gaus(0, 1);
+      pz = px*px + py*py;
+      Float_t rnd = random.Rndm(1);
+      hpx->Fill(px);
+      hpxpy->Fill(px,py);
+      hprof->Fill(px,pz);
+      ntuple->Fill(px,py,pz,rnd,i);
+      if (i && (i%kUPDATE) == 0) {
+         if (i == kUPDATE) hpx->Draw();
+         c1->Modified();
+         c1->Update();
+         if (gSystem->ProcessEvents())
+            break;
+      }
+   }
+   gBenchmark->Show("hsimple");
+
+   // Save all objects in this file
+   hpx->SetFillColor(0);
+   hfile->Write();
+   hpx->SetFillColor(48);
+   c1->Modified();
+   return hfile;
+  
+// Note that the file is automatically close when application terminates
+// or when the file destructor is called.
+}
diff --git a/pypy/module/cppyy/bench/hsimple.py b/pypy/module/cppyy/bench/hsimple.py
new file mode 100755
--- /dev/null
+++ b/pypy/module/cppyy/bench/hsimple.py
@@ -0,0 +1,110 @@
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+#*-*
+#*-*  This program creates :
+#*-*    - a one dimensional histogram
+#*-*    - a two dimensional histogram
+#*-*    - a profile histogram
+#*-*    - a memory-resident ntuple
+#*-*
+#*-*  These objects are filled with some random numbers and saved on a file.
+#*-*
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+
+_reflex = True     # to keep things equal, set to False for full macro
+
+try:
+    import cppyy, random
+
+    if not hasattr(cppyy.gbl, 'gROOT'):
+        cppyy.load_reflection_info('bench02Dict_reflex.so')
+        _reflex = True
+
+    TCanvas  = cppyy.gbl.TCanvas
+    TFile    = cppyy.gbl.TFile
+    TProfile = cppyy.gbl.TProfile
+    TNtuple  = cppyy.gbl.TNtuple
+    TH1F     = cppyy.gbl.TH1F
+    TH2F     = cppyy.gbl.TH2F
+    TRandom3 = cppyy.gbl.TRandom3
+
+    gROOT      = cppyy.gbl.gROOT
+    gBenchmark = cppyy.gbl.TBenchmark()
+    gSystem    = cppyy.gbl.gSystem
+
+except ImportError:
+    from ROOT import TCanvas, TFile, TProfile, TNtuple, TH1F, TH2F, TRandom3
+    from ROOT import gROOT, gBenchmark, gSystem
+    import random
+
+if _reflex:
+   gROOT.SetBatch(True)
+
+# Create a new ROOT binary machine independent file.
+# Note that this file may contain any kind of ROOT objects, histograms,
+# pictures, graphics objects, detector geometries, tracks, events, etc..
+# This file is now becoming the current directory.
+
+if not _reflex:
+    hfile = gROOT.FindObject('hsimple.root')
+    if hfile:
+        hfile.Close()
+    hfile = TFile('hsimple.root', 'RECREATE', 'Demo ROOT file with histograms' )
+
+# Create some histograms, a profile histogram and an ntuple
+hpx    = TH1F('hpx', 'This is the px distribution', 100, -4, 4)
+hpx.SetFillColor(48)
+hpxpy  = TH2F('hpxpy', 'py vs px', 40, -4, 4, 40, -4, 4)
+hprof  = TProfile('hprof', 'Profile of pz versus px', 100, -4, 4, 0, 20)
+if not _reflex:
+    ntuple = TNtuple('ntuple', 'Demo ntuple', 'px:py:pz:random:i')
+
+gBenchmark.Start('hsimple')
+
+# Create a new canvas, and customize it.
+c1 = TCanvas('c1', 'Dynamic Filling Example', 200, 10, 700, 500)
+c1.SetFillColor(42)
+c1.GetFrame().SetFillColor(21)
+c1.GetFrame().SetBorderSize(6)
+c1.GetFrame().SetBorderMode(-1)
+
+# Fill histograms randomly.
+random = TRandom3()
+kUPDATE = 1000
+for i in xrange(50000):
+    # Generate random numbers
+#    px, py = random.gauss(0, 1), random.gauss(0, 1)
+    px, py = random.Gaus(0, 1), random.Gaus(0, 1)
+    pz = px*px + py*py
+#    rnd = random.random()
+    rnd = random.Rndm(1)
+
+    # Fill histograms
+    hpx.Fill(px)
+    hpxpy.Fill(px, py)
+    hprof.Fill(px, pz)
+    if not _reflex:
+        ntuple.Fill(px, py, pz, rnd, i)
+
+    # Update display every kUPDATE events
+    if i and i%kUPDATE == 0:
+        if i == kUPDATE:
+            hpx.Draw()
+
+        c1.Modified(True)
+        c1.Update()
+
+        if gSystem.ProcessEvents():          # allow user interrupt
+            break
+
+gBenchmark.Show( 'hsimple' )
+
+# Save all objects in this file
+hpx.SetFillColor(0)
+if not _reflex:
+    hfile.Write()
+hpx.SetFillColor(48)
+c1.Modified(True)
+c1.Update()
+
+# Note that the file is automatically closed when application terminates
+# or when the file destructor is called.
diff --git a/pypy/module/cppyy/bench/hsimple_rflx.py b/pypy/module/cppyy/bench/hsimple_rflx.py
new file mode 100755
--- /dev/null
+++ b/pypy/module/cppyy/bench/hsimple_rflx.py
@@ -0,0 +1,120 @@
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+#*-*
+#*-*  This program creates :
+#*-*    - a one dimensional histogram
+#*-*    - a two dimensional histogram
+#*-*    - a profile histogram
+#*-*    - a memory-resident ntuple
+#*-*
+#*-*  These objects are filled with some random numbers and saved on a file.
+#*-*
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+
+try:
+    import warnings
+    warnings.simplefilter("ignore")
+
+    import cppyy, random
+    cppyy.load_reflection_info('bench02Dict_reflex.so')
+
+    app      = cppyy.gbl.Bench02RootApp()
+    TCanvas  = cppyy.gbl.TCanvas
+    TFile    = cppyy.gbl.TFile
+    TProfile = cppyy.gbl.TProfile
+    TNtuple  = cppyy.gbl.TNtuple
+    TH1F     = cppyy.gbl.TH1F
+    TH2F     = cppyy.gbl.TH2F
+    TRandom  = cppyy.gbl.TRandom
+except ImportError:
+    from ROOT import TCanvas, TFile, TProfile, TNtuple, TH1F, TH2F, TRandom
+    import random
+
+import math
+
+#gROOT      = cppyy.gbl.gROOT
+#gBenchmark = cppyy.gbl.gBenchmark
+#gRandom    = cppyy.gbl.gRandom
+#gSystem    = cppyy.gbl.gSystem
+
+#gROOT.Reset()
+
+# Create a new canvas, and customize it.
+#c1 = TCanvas( 'c1', 'Dynamic Filling Example', 200, 10, 700, 500 )
+#c1.SetFillColor( 42 )
+#c1.GetFrame().SetFillColor( 21 )
+#c1.GetFrame().SetBorderSize( 6 )
+#c1.GetFrame().SetBorderMode( -1 )
+
+# Create a new ROOT binary machine independent file.
+# Note that this file may contain any kind of ROOT objects, histograms,
+# pictures, graphics objects, detector geometries, tracks, events, etc..
+# This file is now becoming the current directory.
+
+#hfile = gROOT.FindObject( 'hsimple.root' )
+#if hfile:
+#   hfile.Close()
+#hfile = TFile( 'hsimple.root', 'RECREATE', 'Demo ROOT file with histograms' )
+
+# Create some histograms, a profile histogram and an ntuple
+hpx    = TH1F('hpx', 'This is the px distribution', 100, -4, 4)
+hpx.Print()
+#hpxpy  = TH2F( 'hpxpy', 'py vs px', 40, -4, 4, 40, -4, 4 )
+#hprof  = TProfile( 'hprof', 'Profile of pz versus px', 100, -4, 4, 0, 20 )
+#ntuple = TNtuple( 'ntuple', 'Demo ntuple', 'px:py:pz:random:i' )
+
+# Set canvas/frame attributes.
+#hpx.SetFillColor( 48 )
+
+#gBenchmark.Start( 'hsimple' )
+
+# Initialize random number generator.
+#gRandom.SetSeed()
+#rannor, rndm = gRandom.Rannor, gRandom.Rndm
+
+random = TRandom()
+random.SetSeed(0)
+
+# Fill histograms randomly.
+#px, py = Double(), Double()
+kUPDATE = 1000
+for i in xrange(2500000):
+ # Generate random values.
+#   px, py = random.gauss(0, 1), random.gauss(0, 1)
+   px, py = random.Gaus(0, 1), random.Gaus(0, 1)
+#   pt = (px*px + py*py)**0.5
+   pt = math.sqrt(px*px + py*py)
+#   pt = (px*px + py*py)
+#   random = rndm(1)
+
+ # Fill histograms.
+   hpx.Fill(pt)
+#   hpxpyFill( px, py )
+#   hprofFill( px, pz )
+#   ntupleFill( px, py, pz, random, i )
+
+ # Update display every kUPDATE events.
+#   if i and i%kUPDATE == 0:
+#      if i == kUPDATE:
+#         hpx.Draw()
+
+#      c1.Modified()
+#      c1.Update()
+
+#      if gSystem.ProcessEvents():            # allow user interrupt
+#         break
+
+#gBenchmark.Show( 'hsimple' )
+
+hpx.Print() 
+
+# Save all objects in this file.
+#hpx.SetFillColor( 0 )
+#hfile.Write()
+#hfile.Close()
+#hpx.SetFillColor( 48 )
+#c1.Modified()
+#c1.Update()
+#c1.Draw()
+
+# Note that the file is automatically closed when application terminates
+# or when the file destructor is called.
diff --git a/pypy/module/cppyy/capi/__init__.py b/pypy/module/cppyy/capi/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/__init__.py
@@ -0,0 +1,450 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib import jit
+
+import reflex_capi as backend
+#import cint_capi as backend
+
+identify = backend.identify
+ts_reflect = backend.ts_reflect
+ts_call    = backend.ts_call
+ts_memory  = backend.ts_memory
+ts_helper  = backend.ts_helper
+
+_C_OPAQUE_PTR = rffi.LONG
+_C_OPAQUE_NULL = lltype.nullptr(rffi.LONGP.TO)# ALT: _C_OPAQUE_PTR.TO
+
+C_SCOPE = _C_OPAQUE_PTR
+C_NULL_SCOPE = rffi.cast(C_SCOPE, _C_OPAQUE_NULL)
+
+C_TYPE = C_SCOPE
+C_NULL_TYPE = C_NULL_SCOPE
+
+C_OBJECT = _C_OPAQUE_PTR
+C_NULL_OBJECT = rffi.cast(C_OBJECT, _C_OPAQUE_NULL)
+
+C_METHOD = _C_OPAQUE_PTR
+
+C_METHPTRGETTER = lltype.FuncType([C_OBJECT], rffi.VOIDP)
+C_METHPTRGETTER_PTR = lltype.Ptr(C_METHPTRGETTER)
+
+def direct_ptradd(ptr, offset):
+    offset = rffi.cast(rffi.SIZE_T, offset)
+    jit.promote(offset)
+    assert lltype.typeOf(ptr) == C_OBJECT
+    address = rffi.cast(rffi.CCHARP, ptr)
+    return rffi.cast(C_OBJECT, lltype.direct_ptradd(address, offset))
+
+c_load_dictionary = backend.c_load_dictionary
+
+# name to opaque C++ scope representation ------------------------------------
+_c_resolve_name = rffi.llexternal(
+    "cppyy_resolve_name",
+    [rffi.CCHARP], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_resolve_name(name):
+    return charp2str_free(_c_resolve_name(name))
+c_get_scope_opaque = rffi.llexternal(
+    "cppyy_get_scope",
+    [rffi.CCHARP], C_SCOPE,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+c_get_template = rffi.llexternal(
+    "cppyy_get_template",
+    [rffi.CCHARP], C_TYPE,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+_c_actual_class = rffi.llexternal(
+    "cppyy_actual_class",
+    [C_TYPE, C_OBJECT], C_TYPE,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_actual_class(cppclass, cppobj):
+    return _c_actual_class(cppclass.handle, cppobj)
+
+# memory management ----------------------------------------------------------
+_c_allocate = rffi.llexternal(
+    "cppyy_allocate",
+    [C_TYPE], C_OBJECT,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci)
+def c_allocate(cppclass):
+    return _c_allocate(cppclass.handle)
+_c_deallocate = rffi.llexternal(
+    "cppyy_deallocate",
+    [C_TYPE, C_OBJECT], lltype.Void,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci)
+def c_deallocate(cppclass, cppobject):
+    _c_deallocate(cppclass.handle, cppobject)
+_c_destruct = rffi.llexternal(
+    "cppyy_destruct",
+    [C_TYPE, C_OBJECT], lltype.Void,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+def c_destruct(cppclass, cppobject):
+    _c_destruct(cppclass.handle, cppobject)
+
+# method/function dispatching ------------------------------------------------
+c_call_v = rffi.llexternal(
+    "cppyy_call_v",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], lltype.Void,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_b = rffi.llexternal(
+    "cppyy_call_b",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_c = rffi.llexternal(
+    "cppyy_call_c",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.CHAR,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_h = rffi.llexternal(
+    "cppyy_call_h",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.SHORT,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_i = rffi.llexternal(
+    "cppyy_call_i",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_l = rffi.llexternal(
+    "cppyy_call_l",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.LONG,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_ll = rffi.llexternal(
+    "cppyy_call_ll",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.LONGLONG,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_f = rffi.llexternal(
+    "cppyy_call_f",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_d = rffi.llexternal(
+    "cppyy_call_d",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+
+c_call_r = rffi.llexternal(
+    "cppyy_call_r",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.VOIDP,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+c_call_s = rffi.llexternal(
+    "cppyy_call_s",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.CCHARP,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+
+c_constructor = rffi.llexternal(
+    "cppyy_constructor",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], lltype.Void,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+
+_c_call_o = rffi.llexternal(
+    "cppyy_call_o",
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP, C_TYPE], rffi.LONG,
+    threadsafe=ts_call,
+    compilation_info=backend.eci)
+def c_call_o(method_index, cppobj, nargs, args, cppclass):
+    return _c_call_o(method_index, cppobj, nargs, args, cppclass.handle)
+
+_c_get_methptr_getter = rffi.llexternal(
+    "cppyy_get_methptr_getter",
+    [C_SCOPE, rffi.INT], C_METHPTRGETTER_PTR,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci,
+    elidable_function=True)
+def c_get_methptr_getter(cppscope, method_index):
+    return _c_get_methptr_getter(cppscope.handle, method_index)
+
+# handling of function argument buffer ---------------------------------------
+c_allocate_function_args = rffi.llexternal(
+    "cppyy_allocate_function_args",
+    [rffi.SIZE_T], rffi.VOIDP,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci)
+c_deallocate_function_args = rffi.llexternal(
+    "cppyy_deallocate_function_args",
+    [rffi.VOIDP], lltype.Void,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci)
+c_function_arg_sizeof = rffi.llexternal(
+    "cppyy_function_arg_sizeof",
+    [], rffi.SIZE_T,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci,
+    elidable_function=True)
+c_function_arg_typeoffset = rffi.llexternal(
+    "cppyy_function_arg_typeoffset",
+    [], rffi.SIZE_T,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci,
+    elidable_function=True)
+
+# scope reflection information -----------------------------------------------
+c_is_namespace = rffi.llexternal(
+    "cppyy_is_namespace",
+    [C_SCOPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+c_is_enum = rffi.llexternal(
+    "cppyy_is_enum",
+    [rffi.CCHARP], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+
+# type/class reflection information ------------------------------------------
+_c_final_name = rffi.llexternal(
+    "cppyy_final_name",
+    [C_TYPE], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_final_name(cpptype):
+    return charp2str_free(_c_final_name(cpptype))
+_c_scoped_final_name = rffi.llexternal(
+    "cppyy_scoped_final_name",
+    [C_TYPE], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_scoped_final_name(cpptype):
+    return charp2str_free(_c_scoped_final_name(cpptype))
+c_has_complex_hierarchy = rffi.llexternal(
+    "cppyy_has_complex_hierarchy",
+    [C_TYPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+_c_num_bases = rffi.llexternal(
+    "cppyy_num_bases",
+    [C_TYPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_num_bases(cppclass):
+    return _c_num_bases(cppclass.handle)
+_c_base_name = rffi.llexternal(
+    "cppyy_base_name",
+    [C_TYPE, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_base_name(cppclass, base_index):
+    return charp2str_free(_c_base_name(cppclass.handle, base_index))
+
+_c_is_subtype = rffi.llexternal(
+    "cppyy_is_subtype",
+    [C_TYPE, C_TYPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci,
+    elidable_function=True)
+ at jit.elidable_promote()
+def c_is_subtype(derived, base):
+    if derived == base:
+        return 1
+    return _c_is_subtype(derived.handle, base.handle)
+
+_c_base_offset = rffi.llexternal(
+    "cppyy_base_offset",
+    [C_TYPE, C_TYPE, C_OBJECT, rffi.INT], rffi.SIZE_T,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci,
+    elidable_function=True)
+ at jit.elidable_promote()
+def c_base_offset(derived, base, address, direction):
+    if derived == base:
+        return 0
+    return _c_base_offset(derived.handle, base.handle, address, direction)
+
+# method/function reflection information -------------------------------------
+_c_num_methods = rffi.llexternal(
+    "cppyy_num_methods",
+    [C_SCOPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_num_methods(cppscope):
+    return _c_num_methods(cppscope.handle)
+_c_method_name = rffi.llexternal(
+    "cppyy_method_name",
+    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_name(cppscope, method_index):
+    return charp2str_free(_c_method_name(cppscope.handle, method_index))
+_c_method_result_type = rffi.llexternal(
+    "cppyy_method_result_type",
+    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_result_type(cppscope, method_index):
+    return charp2str_free(_c_method_result_type(cppscope.handle, method_index))
+_c_method_num_args = rffi.llexternal(
+    "cppyy_method_num_args",
+    [C_SCOPE, rffi.INT], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_num_args(cppscope, method_index):
+    return _c_method_num_args(cppscope.handle, method_index)
+_c_method_req_args = rffi.llexternal(
+    "cppyy_method_req_args",
+    [C_SCOPE, rffi.INT], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_req_args(cppscope, method_index):
+    return _c_method_req_args(cppscope.handle, method_index)
+_c_method_arg_type = rffi.llexternal(
+    "cppyy_method_arg_type",
+    [C_SCOPE, rffi.INT, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_arg_type(cppscope, method_index, arg_index):
+    return charp2str_free(_c_method_arg_type(cppscope.handle, method_index, arg_index))
+_c_method_arg_default = rffi.llexternal(
+    "cppyy_method_arg_default",
+    [C_SCOPE, rffi.INT, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_arg_default(cppscope, method_index, arg_index):
+    return charp2str_free(_c_method_arg_default(cppscope.handle, method_index, arg_index))
+_c_method_signature = rffi.llexternal(
+    "cppyy_method_signature",
+    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_signature(cppscope, method_index):
+    return charp2str_free(_c_method_signature(cppscope.handle, method_index))
+
+_c_method_index = rffi.llexternal(
+    "cppyy_method_index",
+    [C_SCOPE, rffi.CCHARP], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_index(cppscope, name):
+    return _c_method_index(cppscope.handle, name)
+
+_c_get_method = rffi.llexternal(
+    "cppyy_get_method",
+    [C_SCOPE, rffi.INT], C_METHOD,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_get_method(cppscope, method_index):
+    return _c_get_method(cppscope.handle, method_index)
+
+# method properties ----------------------------------------------------------
+_c_is_constructor = rffi.llexternal(
+    "cppyy_is_constructor",
+    [C_TYPE, rffi.INT], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_is_constructor(cppclass, method_index):
+    return _c_is_constructor(cppclass.handle, method_index)
+_c_is_staticmethod = rffi.llexternal(
+    "cppyy_is_staticmethod",
+    [C_TYPE, rffi.INT], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_is_staticmethod(cppclass, method_index):
+    return _c_is_staticmethod(cppclass.handle, method_index)
+
+# data member reflection information -----------------------------------------
+_c_num_datamembers = rffi.llexternal(
+    "cppyy_num_datamembers",
+    [C_SCOPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_num_datamembers(cppscope):
+    return _c_num_datamembers(cppscope.handle)
+_c_datamember_name = rffi.llexternal(
+    "cppyy_datamember_name",
+    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_datamember_name(cppscope, datamember_index):
+    return charp2str_free(_c_datamember_name(cppscope.handle, datamember_index))
+_c_datamember_type = rffi.llexternal(
+    "cppyy_datamember_type",
+    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_datamember_type(cppscope, datamember_index):
+    return charp2str_free(_c_datamember_type(cppscope.handle, datamember_index))
+_c_datamember_offset = rffi.llexternal(
+    "cppyy_datamember_offset",
+    [C_SCOPE, rffi.INT], rffi.SIZE_T,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_datamember_offset(cppscope, datamember_index):
+    return _c_datamember_offset(cppscope.handle, datamember_index)
+
+_c_datamember_index = rffi.llexternal(
+    "cppyy_datamember_index",
+    [C_SCOPE, rffi.CCHARP], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_datamember_index(cppscope, name):
+    return _c_datamember_index(cppscope.handle, name)
+
+# data member properties -----------------------------------------------------
+_c_is_publicdata = rffi.llexternal(
+    "cppyy_is_publicdata",
+    [C_SCOPE, rffi.INT], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_is_publicdata(cppscope, datamember_index):
+    return _c_is_publicdata(cppscope.handle, datamember_index)
+_c_is_staticdata = rffi.llexternal(
+    "cppyy_is_staticdata",
+    [C_SCOPE, rffi.INT], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_is_staticdata(cppscope, datamember_index):
+    return _c_is_staticdata(cppscope.handle, datamember_index)
+
+# misc helpers ---------------------------------------------------------------
+c_strtoll = rffi.llexternal(
+    "cppyy_strtoll",
+    [rffi.CCHARP], rffi.LONGLONG,
+    threadsafe=ts_helper,
+    compilation_info=backend.eci)
+c_strtoull = rffi.llexternal(
+    "cppyy_strtoull",
+    [rffi.CCHARP], rffi.ULONGLONG,
+    threadsafe=ts_helper,
+    compilation_info=backend.eci)
+c_free = rffi.llexternal(
+    "cppyy_free",
+    [rffi.VOIDP], lltype.Void,
+    threadsafe=ts_memory,
+    compilation_info=backend.eci)
+
+def charp2str_free(charp):
+    string = rffi.charp2str(charp)
+    voidp = rffi.cast(rffi.VOIDP, charp)
+    c_free(voidp)
+    return string
+
+c_charp2stdstring = rffi.llexternal(
+    "cppyy_charp2stdstring",
+    [rffi.CCHARP], C_OBJECT,
+    threadsafe=ts_helper,
+    compilation_info=backend.eci)
+c_stdstring2stdstring = rffi.llexternal(
+    "cppyy_stdstring2stdstring",
+    [C_OBJECT], C_OBJECT,
+    threadsafe=ts_helper,
+    compilation_info=backend.eci)
+c_assign2stdstring = rffi.llexternal(
+    "cppyy_assign2stdstring",
+    [C_OBJECT, rffi.CCHARP], lltype.Void,
+    threadsafe=ts_helper,
+    compilation_info=backend.eci)
+c_free_stdstring = rffi.llexternal(
+    "cppyy_free_stdstring",
+    [C_OBJECT], lltype.Void,
+    threadsafe=ts_helper,
+    compilation_info=backend.eci)
diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/cint_capi.py
@@ -0,0 +1,63 @@
+import py, os
+
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib import libffi, rdynload
+
+__all__ = ['identify', 'eci', 'c_load_dictionary']
+
+pkgpath = py.path.local(__file__).dirpath().join(os.pardir)
+srcpath = pkgpath.join("src")
+incpath = pkgpath.join("include")
+
+if os.environ.get("ROOTSYS"):
+    import commands
+    (stat, incdir) = commands.getstatusoutput("root-config --incdir")
+    if stat != 0:        # presumably Reflex-only
+        rootincpath = [os.path.join(os.environ["ROOTSYS"], "include")]
+        rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
+    else:
+        rootincpath = [incdir]
+        rootlibpath = commands.getoutput("root-config --libdir").split()
+else:
+    rootincpath = []
+    rootlibpath = []
+
+def identify():
+    return 'CINT'
+
+ts_reflect = False
+ts_call    = False
+ts_memory  = 'auto'
+ts_helper  = 'auto'
+
+# force loading in global mode of core libraries, rather than linking with
+# them as PyPy uses various version of dlopen in various places; note that
+# this isn't going to fly on Windows (note that locking them in objects and
+# calling dlclose in __del__ seems to come too late, so this'll do for now)
+with rffi.scoped_str2charp('libCint.so') as ll_libname:
+    _cintdll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
+with rffi.scoped_str2charp('libCore.so') as ll_libname:
+    _coredll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
+
+eci = ExternalCompilationInfo(
+    separate_module_files=[srcpath.join("cintcwrapper.cxx")],
+    include_dirs=[incpath] + rootincpath,
+    includes=["cintcwrapper.h"],
+    library_dirs=rootlibpath,
+    link_extra=["-lCore", "-lCint"],
+    use_cpp_linker=True,
+)
+
+_c_load_dictionary = rffi.llexternal(
+    "cppyy_load_dictionary",
+    [rffi.CCHARP], rdynload.DLLHANDLE,
+    threadsafe=False,
+    compilation_info=eci)
+
+def c_load_dictionary(name):
+    result = _c_load_dictionary(name)
+    if not result:
+        err = rdynload.dlerror()
+        raise rdynload.DLOpenError(err)
+    return libffi.CDLL(name)       # should return handle to already open file
diff --git a/pypy/module/cppyy/capi/reflex_capi.py b/pypy/module/cppyy/capi/reflex_capi.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/reflex_capi.py
@@ -0,0 +1,43 @@
+import py, os
+
+from pypy.rlib import libffi
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+
+__all__ = ['identify', 'eci', 'c_load_dictionary']
+
+pkgpath = py.path.local(__file__).dirpath().join(os.pardir)
+srcpath = pkgpath.join("src")
+incpath = pkgpath.join("include")
+
+if os.environ.get("ROOTSYS"):
+    import commands
+    (stat, incdir) = commands.getstatusoutput("root-config --incdir")
+    if stat != 0:        # presumably Reflex-only
+        rootincpath = [os.path.join(os.environ["ROOTSYS"], "include")]
+        rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
+    else:
+        rootincpath = [incdir]
+        rootlibpath = commands.getoutput("root-config --libdir").split()
+else:
+    rootincpath = []
+    rootlibpath = []
+
+def identify():
+    return 'Reflex'
+
+ts_reflect = False
+ts_call    = 'auto'
+ts_memory  = 'auto'
+ts_helper  = 'auto'
+
+eci = ExternalCompilationInfo(
+    separate_module_files=[srcpath.join("reflexcwrapper.cxx")],
+    include_dirs=[incpath] + rootincpath,
+    includes=["reflexcwrapper.h"],
+    library_dirs=rootlibpath,
+    link_extra=["-lReflex"],
+    use_cpp_linker=True,
+)
+
+def c_load_dictionary(name):
+    return libffi.CDLL(name)
diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/converter.py
@@ -0,0 +1,832 @@
+import sys
+
+from pypy.interpreter.error import OperationError
+
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib.rarithmetic import r_singlefloat
+from pypy.rlib import jit, libffi, clibffi, rfloat
+
+from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+from pypy.module._rawffi.array import W_Array
+
+from pypy.module.cppyy import helper, capi
+
+
+def get_rawobject(space, w_obj):
+    from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+    cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+    if cppinstance:
+        rawobject = cppinstance.get_rawobject()
+        assert lltype.typeOf(rawobject) == capi.C_OBJECT
+        return rawobject
+    return capi.C_NULL_OBJECT
+
+def set_rawobject(space, w_obj, address):
+    from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+    cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+    if cppinstance:
+        assert lltype.typeOf(cppinstance._rawobject) == capi.C_OBJECT
+        cppinstance._rawobject = rffi.cast(capi.C_OBJECT, address)
+
+def get_rawobject_nonnull(space, w_obj):
+    from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+    cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+    if cppinstance:
+        cppinstance._nullcheck()
+        rawobject = cppinstance.get_rawobject()
+        assert lltype.typeOf(rawobject) == capi.C_OBJECT
+        return rawobject
+    return capi.C_NULL_OBJECT
+
+
+class TypeConverter(object):
+    _immutable_ = True
+    libffitype = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+    uses_local = False
+
+    name = ""
+
+    def __init__(self, space, extra):
+        pass
+
+    def _get_raw_address(self, space, w_obj, offset):
+        rawobject = get_rawobject_nonnull(space, w_obj)
+        assert lltype.typeOf(rawobject) == capi.C_OBJECT
+        if rawobject:
+            fieldptr = capi.direct_ptradd(rawobject, offset)
+        else:
+            fieldptr = rffi.cast(capi.C_OBJECT, offset)
+        return fieldptr
+
+    def _is_abstract(self, space):
+        raise OperationError(space.w_TypeError, space.wrap("no converter available"))
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        self._is_abstract(space)
+
+    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+    def default_argument_libffi(self, space, argchain):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        self._is_abstract(space)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        self._is_abstract(space)
+
+    def finalize_call(self, space, w_obj, call_local):
+        pass
+
+    def free_argument(self, space, arg, call_local):
+        pass
+
+
+class ArrayCache(object):
+    def __init__(self, space):
+        self.space = space
+    def __getattr__(self, name):
+        if name.startswith('array_'):
+            typecode = name[len('array_'):]
+            arr = self.space.interp_w(W_Array, unpack_simple_shape(self.space, self.space.wrap(typecode)))
+            setattr(self, name, arr)
+            return arr
+        raise AttributeError(name)
+
+    def _freeze_(self):
+        return True
+
+class ArrayTypeConverterMixin(object):
+    _mixin_ = True
+    _immutable_ = True
+
+    def __init__(self, space, array_size):
+        if array_size <= 0:
+            self.size = sys.maxint
+        else:
+            self.size = array_size
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        # read access, so no copy needed
+        address_value = self._get_raw_address(space, w_obj, offset)
+        address = rffi.cast(rffi.ULONG, address_value)
+        cache = space.fromcache(ArrayCache)
+        arr = getattr(cache, 'array_' + self.typecode)
+        return arr.fromaddress(space, address, self.size)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        # copy the full array (uses byte copy for now)
+        address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+        buf = space.buffer_w(w_value)
+        # TODO: report if too many items given?
+        for i in range(min(self.size*self.typesize, buf.getlength())):
+            address[i] = buf.getitem(i)
+
+
+class PtrTypeConverterMixin(object):
+    _mixin_ = True
+    _immutable_ = True
+
+    def __init__(self, space, array_size):
+        self.size = sys.maxint
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        # read access, so no copy needed
+        address_value = self._get_raw_address(space, w_obj, offset)
+        address = rffi.cast(rffi.ULONGP, address_value)
+        cache = space.fromcache(ArrayCache)
+        arr = getattr(cache, 'array_' + self.typecode)
+        return arr.fromaddress(space, address[0], self.size)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        # copy only the pointer value
+        rawobject = get_rawobject_nonnull(space, w_obj)
+        byteptr = rffi.cast(rffi.CCHARPP, capi.direct_ptradd(rawobject, offset))
+        buf = space.buffer_w(w_value)
+        try:
+            byteptr[0] = buf.get_raw_address()
+        except ValueError:
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("raw buffer interface not supported"))
+
+
+class NumericTypeConverterMixin(object):
+    _mixin_ = True
+    _immutable_ = True
+
+    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+        argchain.arg(self._unwrap_object(space, w_obj))
+
+    def default_argument_libffi(self, space, argchain):
+        argchain.arg(self.default)
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = self._get_raw_address(space, w_obj, offset)
+        rffiptr = rffi.cast(self.c_ptrtype, address)
+        return space.wrap(rffiptr[0])
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        address = self._get_raw_address(space, w_obj, offset)
+        rffiptr = rffi.cast(self.c_ptrtype, address)
+        rffiptr[0] = self._unwrap_object(space, w_value)
+
+class ConstRefNumericTypeConverterMixin(NumericTypeConverterMixin):
+    _mixin_ = True
+    _immutable_ = True
+    uses_local = True
+
+    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+        assert rffi.sizeof(self.c_type) <= 2*rffi.sizeof(rffi.VOIDP)  # see interp_cppyy.py
+        obj = self._unwrap_object(space, w_obj)
+        typed_buf = rffi.cast(self.c_ptrtype, call_local)
+        typed_buf[0] = obj
+        argchain.arg(call_local)
+
+class IntTypeConverterMixin(NumericTypeConverterMixin):
+    _mixin_ = True
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self._unwrap_object(space, w_obj)
+
+class FloatTypeConverterMixin(NumericTypeConverterMixin):
+    _mixin_ = True
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self._unwrap_object(space, w_obj)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = self.typecode
+
+
+class VoidConverter(TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.void
+
+    def __init__(self, space, name):
+        self.name = name
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        raise OperationError(space.w_TypeError,
+                             space.wrap('no converter available for type "%s"' % self.name))
+
+
+class BoolConverter(TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.schar
+
+    def _unwrap_object(self, space, w_obj):
+        arg = space.c_int_w(w_obj)
+        if arg != False and arg != True:
+            raise OperationError(space.w_ValueError,
+                                 space.wrap("boolean value should be bool, or integer 1 or 0"))
+        return arg
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.LONGP, address)
+        x[0] = self._unwrap_object(space, w_obj)
+
+    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+        argchain.arg(self._unwrap_object(space, w_obj))
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+        if address[0] == '\x01':
+            return space.w_True
+        return space.w_False
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+        arg = self._unwrap_object(space, w_value)
+        if arg:
+            address[0] = '\x01'
+        else:
+            address[0] = '\x00'
+
+class CharConverter(TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.schar
+
+    def _unwrap_object(self, space, w_value):
+        # allow int to pass to char and make sure that str is of length 1
+        if space.isinstance_w(w_value, space.w_int):
+            ival = space.c_int_w(w_value)
+            if ival < 0 or 256 <= ival:
+                raise OperationError(space.w_ValueError,
+                                     space.wrap("char arg not in range(256)"))
+
+            value = rffi.cast(rffi.CHAR, space.c_int_w(w_value))
+        else:
+            value = space.str_w(w_value)
+
+        if len(value) != 1:  
+            raise OperationError(space.w_ValueError,
+                                 space.wrap("char expected, got string of size %d" % len(value)))
+        return value[0] # turn it into a "char" to the annotator
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.CCHARP, address)
+        x[0] = self._unwrap_object(space, w_obj)
+
+    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+        argchain.arg(self._unwrap_object(space, w_obj))
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+        return space.wrap(address[0])
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+        address[0] = self._unwrap_object(space, w_value)
+
+
+class ShortConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.sshort
+    c_type     = rffi.SHORT
+    c_ptrtype  = rffi.SHORTP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(rffi.SHORT, capi.c_strtoll(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(rffi.SHORT, space.int_w(w_obj))
+
+class ConstShortRefConverter(ConstRefNumericTypeConverterMixin, ShortConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+class UnsignedShortConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.sshort
+    c_type     = rffi.USHORT
+    c_ptrtype  = rffi.USHORTP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(self.c_type, space.int_w(w_obj))
+
+class ConstUnsignedShortRefConverter(ConstRefNumericTypeConverterMixin, UnsignedShortConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+class IntConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.sint
+    c_type     = rffi.INT
+    c_ptrtype  = rffi.INTP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(self.c_type, space.c_int_w(w_obj))
+
+class ConstIntRefConverter(ConstRefNumericTypeConverterMixin, IntConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+class UnsignedIntConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.uint
+    c_type     = rffi.UINT
+    c_ptrtype  = rffi.UINTP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(self.c_type, space.uint_w(w_obj))
+
+class ConstUnsignedIntRefConverter(ConstRefNumericTypeConverterMixin, UnsignedIntConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+class LongConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.slong
+    c_type     = rffi.LONG
+    c_ptrtype  = rffi.LONGP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return space.int_w(w_obj)
+
+class ConstLongRefConverter(ConstRefNumericTypeConverterMixin, LongConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+    typecode = 'r'
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self._unwrap_object(space, w_obj)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = self.typecode
+
+class LongLongConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.slong
+    c_type     = rffi.LONGLONG
+    c_ptrtype  = rffi.LONGLONGP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return space.r_longlong_w(w_obj)
+
+class ConstLongLongRefConverter(ConstRefNumericTypeConverterMixin, LongLongConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+    typecode = 'r'
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self._unwrap_object(space, w_obj)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = self.typecode
+
+class UnsignedLongConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.ulong
+    c_type     = rffi.ULONG
+    c_ptrtype  = rffi.ULONGP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return space.uint_w(w_obj)
+
+class ConstUnsignedLongRefConverter(ConstRefNumericTypeConverterMixin, UnsignedLongConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+class UnsignedLongLongConverter(IntTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.ulong
+    c_type     = rffi.ULONGLONG
+    c_ptrtype  = rffi.ULONGLONGP
+
+    def __init__(self, space, default):
+        self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+    def _unwrap_object(self, space, w_obj):
+        return space.r_ulonglong_w(w_obj)
+
+class ConstUnsignedLongLongRefConverter(ConstRefNumericTypeConverterMixin, UnsignedLongLongConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+
+class FloatConverter(FloatTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.float
+    c_type     = rffi.FLOAT
+    c_ptrtype  = rffi.FLOATP
+    typecode   = 'f'
+
+    def __init__(self, space, default):
+        if default:
+            fval = float(rfloat.rstring_to_float(default))
+        else:
+            fval = float(0.)
+        self.default = r_singlefloat(fval)
+
+    def _unwrap_object(self, space, w_obj):
+        return r_singlefloat(space.float_w(w_obj))
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = self._get_raw_address(space, w_obj, offset)
+        rffiptr = rffi.cast(self.c_ptrtype, address)
+        return space.wrap(float(rffiptr[0]))
+
+class ConstFloatRefConverter(FloatConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+    typecode = 'F'
+
+    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+class DoubleConverter(FloatTypeConverterMixin, TypeConverter):
+    _immutable_ = True
+    libffitype = libffi.types.double
+    c_type     = rffi.DOUBLE
+    c_ptrtype  = rffi.DOUBLEP
+    typecode   = 'd'
+
+    def __init__(self, space, default):
+        if default:
+            self.default = rffi.cast(self.c_type, rfloat.rstring_to_float(default))
+        else:
+            self.default = rffi.cast(self.c_type, 0.)
+
+    def _unwrap_object(self, space, w_obj):
+        return space.float_w(w_obj)
+
+class ConstDoubleRefConverter(ConstRefNumericTypeConverterMixin, DoubleConverter):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+    typecode = 'D'
+
+
+class CStringConverter(TypeConverter):
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.LONGP, address)
+        arg = space.str_w(w_obj)
+        x[0] = rffi.cast(rffi.LONG, rffi.str2charp(arg))
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'o'
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = self._get_raw_address(space, w_obj, offset)
+        charpptr = rffi.cast(rffi.CCHARPP, address)
+        return space.wrap(rffi.charp2str(charpptr[0]))
+
+    def free_argument(self, space, arg, call_local):
+        lltype.free(rffi.cast(rffi.CCHARPP, arg)[0], flavor='raw')
+
+
+class VoidPtrConverter(TypeConverter):
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'a'
+
+    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+        argchain.arg(get_rawobject(space, w_obj))
+
+class VoidPtrPtrConverter(TypeConverter):
+    _immutable_ = True
+    uses_local = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        r = rffi.cast(rffi.VOIDPP, call_local)
+        r[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, call_local)
+        address = rffi.cast(capi.C_OBJECT, address)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'a'
+
+    def finalize_call(self, space, w_obj, call_local):
+        r = rffi.cast(rffi.VOIDPP, call_local)
+        set_rawobject(space, w_obj, r[0])
+
+class VoidPtrRefConverter(TypeConverter):
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'r'
+
+
+class InstancePtrConverter(TypeConverter):
+    _immutable_ = True
+
+    def __init__(self, space, cppclass):
+        from pypy.module.cppyy.interp_cppyy import W_CPPClass
+        assert isinstance(cppclass, W_CPPClass)
+        self.cppclass = cppclass
+
+    def _unwrap_object(self, space, w_obj):
+        from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+        obj = space.interpclass_w(w_obj)
+        if isinstance(obj, W_CPPInstance):
+            if capi.c_is_subtype(obj.cppclass, self.cppclass):
+                rawobject = obj.get_rawobject()
+                offset = capi.c_base_offset(obj.cppclass, self.cppclass, rawobject, 1)
+                obj_address = capi.direct_ptradd(rawobject, offset)
+                return rffi.cast(capi.C_OBJECT, obj_address)
+        raise OperationError(space.w_TypeError,
+                             space.wrap("cannot pass %s as %s" %
+                             (space.type(w_obj).getname(space, "?"), self.cppclass.name)))
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
+        address = rffi.cast(capi.C_OBJECT, address)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'o'
+
+    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+        argchain.arg(self._unwrap_object(space, w_obj))
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
+        from pypy.module.cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppobject_nocast(
+            space, w_pycppclass, self.cppclass, address, isref=True, python_owns=False)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset))
+        address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
+
+class InstanceConverter(InstancePtrConverter):
+    _immutable_ = True
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
+        from pypy.module.cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppobject_nocast(
+            space, w_pycppclass, self.cppclass, address, isref=False, python_owns=False)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        self._is_abstract(space)
+
+class InstancePtrPtrConverter(InstancePtrConverter):
+    _immutable_ = True
+    uses_local = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        r = rffi.cast(rffi.VOIDPP, call_local)
+        r[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, call_local)
+        address = rffi.cast(capi.C_OBJECT, address)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'o'
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        self._is_abstract(space)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        self._is_abstract(space)
+
+    def finalize_call(self, space, w_obj, call_local):
+        from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+        obj = space.interpclass_w(w_obj)
+        assert isinstance(obj, W_CPPInstance)
+        r = rffi.cast(rffi.VOIDPP, call_local)
+        obj._rawobject = rffi.cast(capi.C_OBJECT, r[0])
+
+
+class StdStringConverter(InstanceConverter):
+    _immutable_ = True
+
+    def __init__(self, space, extra):
+        from pypy.module.cppyy import interp_cppyy
+        cppclass = interp_cppyy.scope_byname(space, "std::string")
+        InstanceConverter.__init__(self, space, cppclass)
+
+    def _unwrap_object(self, space, w_obj):
+        try:
+           charp = rffi.str2charp(space.str_w(w_obj))
+           arg = capi.c_charp2stdstring(charp)
+           rffi.free_charp(charp)
+           return arg
+        except OperationError:
+           arg = InstanceConverter._unwrap_object(self, space, w_obj)
+           return capi.c_stdstring2stdstring(arg)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        try:
+            address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
+            charp = rffi.str2charp(space.str_w(w_value))
+            capi.c_assign2stdstring(address, charp)
+            rffi.free_charp(charp)
+            return
+        except Exception:
+            pass
+        return InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
+
+    def free_argument(self, space, arg, call_local):
+        capi.c_free_stdstring(rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
+
+class StdStringRefConverter(InstancePtrConverter):
+    _immutable_ = True
+
+    def __init__(self, space, extra):
+        from pypy.module.cppyy import interp_cppyy
+        cppclass = interp_cppyy.scope_byname(space, "std::string")
+        InstancePtrConverter.__init__(self, space, cppclass)
+
+
+class PyObjectConverter(TypeConverter):
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        space.getbuiltinmodule("cpyext")
+        from pypy.module.cpyext.pyobject import make_ref
+        ref = make_ref(space, w_obj)
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, ref);
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'a'
+
+    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        space.getbuiltinmodule("cpyext")
+        from pypy.module.cpyext.pyobject import make_ref
+        ref = make_ref(space, w_obj)
+        argchain.arg(rffi.cast(rffi.VOIDP, ref))
+
+    def free_argument(self, space, arg, call_local):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        from pypy.module.cpyext.pyobject import Py_DecRef, PyObject
+        Py_DecRef(space, rffi.cast(PyObject, rffi.cast(rffi.VOIDPP, arg)[0]))
+
+
+_converters = {}         # builtin and custom types
+_a_converters = {}       # array and ptr versions of above
+def get_converter(space, name, default):
+    # The matching of the name to a converter should follow:
+    #   1) full, exact match
+    #       1a) const-removed match
+    #   2) match of decorated, unqualified type
+    #   3) accept ref as pointer (for the stubs, const& can be
+    #       by value, but that does not work for the ffi path)
+    #   4) generalized cases (covers basically all user classes)
+    #   5) void converter, which fails on use
+
+    name = capi.c_resolve_name(name)
+
+    #   1) full, exact match
+    try:
+        return _converters[name](space, default)
+    except KeyError:
+        pass
+
+    #   1a) const-removed match
+    try:
+        return _converters[helper.remove_const(name)](space, default)
+    except KeyError:
+        pass
+
+    #   2) match of decorated, unqualified type
+    compound = helper.compound(name)
+    clean_name = helper.clean_type(name)
+    try:
+        # array_index may be negative to indicate no size or no size found
+        array_size = helper.array_size(name)
+        return _a_converters[clean_name+compound](space, array_size)
+    except KeyError:
+        pass
+
+    #   3) TODO: accept ref as pointer
+
+    #   4) generalized cases (covers basically all user classes)
+    from pypy.module.cppyy import interp_cppyy
+    cppclass = interp_cppyy.scope_byname(space, clean_name)
+    if cppclass:
+        # type check for the benefit of the annotator
+        from pypy.module.cppyy.interp_cppyy import W_CPPClass
+        cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
+        if compound == "*" or compound == "&":
+            return InstancePtrConverter(space, cppclass)
+        elif compound == "**":
+            return InstancePtrPtrConverter(space, cppclass)
+        elif compound == "":
+            return InstanceConverter(space, cppclass)
+    elif capi.c_is_enum(clean_name):
+        return UnsignedIntConverter(space, default)
+    
+    #   5) void converter, which fails on use
+    #
+    # return a void converter here, so that the class can be build even
+    # when some types are unknown; this overload will simply fail on use
+    return VoidConverter(space, name)
+
+
+_converters["bool"]                     = BoolConverter
+_converters["char"]                     = CharConverter
+_converters["unsigned char"]            = CharConverter
+_converters["short int"]                = ShortConverter
+_converters["const short int&"]         = ConstShortRefConverter
+_converters["short"]                    = _converters["short int"]
+_converters["const short&"]             = _converters["const short int&"]
+_converters["unsigned short int"]       = UnsignedShortConverter
+_converters["const unsigned short int&"] = ConstUnsignedShortRefConverter
+_converters["unsigned short"]           = _converters["unsigned short int"]
+_converters["const unsigned short&"]    = _converters["const unsigned short int&"]
+_converters["int"]                      = IntConverter
+_converters["const int&"]               = ConstIntRefConverter
+_converters["unsigned int"]             = UnsignedIntConverter
+_converters["const unsigned int&"]      = ConstUnsignedIntRefConverter
+_converters["long int"]                 = LongConverter
+_converters["const long int&"]          = ConstLongRefConverter
+_converters["long"]                     = _converters["long int"]
+_converters["const long&"]              = _converters["const long int&"]
+_converters["unsigned long int"]        = UnsignedLongConverter
+_converters["const unsigned long int&"] = ConstUnsignedLongRefConverter
+_converters["unsigned long"]            = _converters["unsigned long int"]
+_converters["const unsigned long&"]     = _converters["const unsigned long int&"]
+_converters["long long int"]            = LongLongConverter
+_converters["const long long int&"]     = ConstLongLongRefConverter
+_converters["long long"]                = _converters["long long int"]
+_converters["const long long&"]         = _converters["const long long int&"]
+_converters["unsigned long long int"]   = UnsignedLongLongConverter
+_converters["const unsigned long long int&"] = ConstUnsignedLongLongRefConverter
+_converters["unsigned long long"]       = _converters["unsigned long long int"]
+_converters["const unsigned long long&"] = _converters["const unsigned long long int&"]
+_converters["float"]                    = FloatConverter
+_converters["const float&"]             = ConstFloatRefConverter
+_converters["double"]                   = DoubleConverter
+_converters["const double&"]            = ConstDoubleRefConverter
+_converters["const char*"]              = CStringConverter
+_converters["char*"]                    = CStringConverter
+_converters["void*"]                    = VoidPtrConverter
+_converters["void**"]                   = VoidPtrPtrConverter
+_converters["void*&"]                   = VoidPtrRefConverter
+
+# special cases (note: CINT backend requires the simple name 'string')
+_converters["std::basic_string<char>"]           = StdStringConverter
+_converters["string"]                            = _converters["std::basic_string<char>"]
+_converters["const std::basic_string<char>&"]    = StdStringConverter     # TODO: shouldn't copy
+_converters["const string&"]                     = _converters["const std::basic_string<char>&"]
+_converters["std::basic_string<char>&"]          = StdStringRefConverter
+_converters["string&"]                           = _converters["std::basic_string<char>&"]
+
+_converters["PyObject*"]                         = PyObjectConverter
+_converters["_object*"]                          = _converters["PyObject*"]
+
+def _build_array_converters():
+    "NOT_RPYTHON"
+    array_info = (
+        ('h', rffi.sizeof(rffi.SHORT),  ("short int", "short")),
+        ('H', rffi.sizeof(rffi.USHORT), ("unsigned short int", "unsigned short")),
+        ('i', rffi.sizeof(rffi.INT),    ("int",)),
+        ('I', rffi.sizeof(rffi.UINT),   ("unsigned int", "unsigned")),
+        ('l', rffi.sizeof(rffi.LONG),   ("long int", "long")),
+        ('L', rffi.sizeof(rffi.ULONG),  ("unsigned long int", "unsigned long")),
+        ('f', rffi.sizeof(rffi.FLOAT),  ("float",)),
+        ('d', rffi.sizeof(rffi.DOUBLE), ("double",)),
+    )
+
+    for info in array_info:
+        class ArrayConverter(ArrayTypeConverterMixin, TypeConverter):
+            _immutable_ = True
+            typecode = info[0]
+            typesize = info[1]
+        class PtrConverter(PtrTypeConverterMixin, TypeConverter):
+            _immutable_ = True
+            typecode = info[0]
+            typesize = info[1]
+        for name in info[2]:
+            _a_converters[name+'[]'] = ArrayConverter
+            _a_converters[name+'*']  = PtrConverter
+_build_array_converters()
diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/executor.py
@@ -0,0 +1,466 @@
+import sys
+
+from pypy.interpreter.error import OperationError
+
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib import libffi, clibffi
+
+from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+from pypy.module._rawffi.array import W_Array
+
+from pypy.module.cppyy import helper, capi
+
+
+NULL = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+
+class FunctionExecutor(object):
+    _immutable_ = True
+    libffitype = NULL
+
+    def __init__(self, space, extra):
+        pass
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        raise OperationError(space.w_TypeError,
+                             space.wrap('return type not available or supported'))
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+
+class PtrTypeExecutor(FunctionExecutor):
+    _immutable_ = True
+    typecode = 'P'
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
+        address = rffi.cast(rffi.ULONG, lresult)
+        arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap(self.typecode)))
+        return arr.fromaddress(space, address, sys.maxint)
+
+
+class VoidExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.void
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        capi.c_call_v(cppmethod, cppthis, num_args, args)
+        return space.w_None
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        libffifunc.call(argchain, lltype.Void)
+        return space.w_None
+
+
+class BoolExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.schar
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_b(cppmethod, cppthis, num_args, args)
+        return space.wrap(result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.CHAR)
+        return space.wrap(bool(ord(result)))
+
+class CharExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.schar
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_c(cppmethod, cppthis, num_args, args)
+        return space.wrap(result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.CHAR)
+        return space.wrap(result)
+
+class ShortExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.sshort
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_h(cppmethod, cppthis, num_args, args)
+        return space.wrap(result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.SHORT)
+        return space.wrap(result)
+
+class IntExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.sint
+
+    def _wrap_result(self, space, result):
+        return space.wrap(result)
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_i(cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.INT)
+        return space.wrap(result)
+
+class UnsignedIntExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.uint
+
+    def _wrap_result(self, space, result):
+        return space.wrap(rffi.cast(rffi.UINT, result))
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_l(cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.UINT)
+        return space.wrap(result)
+
+class LongExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.slong
+
+    def _wrap_result(self, space, result):
+        return space.wrap(result)
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_l(cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.LONG)
+        return space.wrap(result)
+
+class UnsignedLongExecutor(LongExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.ulong
+
+    def _wrap_result(self, space, result):
+        return space.wrap(rffi.cast(rffi.ULONG, result))
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.ULONG)
+        return space.wrap(result)
+
+class LongLongExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.sint64
+
+    def _wrap_result(self, space, result):
+        return space.wrap(result)
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_ll(cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.LONGLONG)
+        return space.wrap(result)
+
+class UnsignedLongLongExecutor(LongLongExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.uint64
+
+    def _wrap_result(self, space, result):
+        return space.wrap(rffi.cast(rffi.ULONGLONG, result))
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.ULONGLONG)
+        return space.wrap(result)
+
+class ConstIntRefExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+    def _wrap_result(self, space, result):
+        intptr = rffi.cast(rffi.INTP, result)
+        return space.wrap(intptr[0])
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_r(cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.INTP)
+        return space.wrap(result[0])
+
+class ConstLongRefExecutor(ConstIntRefExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+    def _wrap_result(self, space, result):
+        longptr = rffi.cast(rffi.LONGP, result)
+        return space.wrap(longptr[0])
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.LONGP)
+        return space.wrap(result[0])
+
+class FloatExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.float
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_f(cppmethod, cppthis, num_args, args)
+        return space.wrap(float(result))
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.FLOAT)
+        return space.wrap(float(result))
+
+class DoubleExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.double
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        result = capi.c_call_d(cppmethod, cppthis, num_args, args)
+        return space.wrap(result)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        result = libffifunc.call(argchain, rffi.DOUBLE)
+        return space.wrap(result)
+
+
+class CStringExecutor(FunctionExecutor):
+    _immutable_ = True
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
+        ccpresult = rffi.cast(rffi.CCHARP, lresult)
+        result = rffi.charp2str(ccpresult)  # TODO: make it a choice to free
+        return space.wrap(result)
+
+
+class ShortPtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'h'
+
+class IntPtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'i'
+
+class UnsignedIntPtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'I'
+
+class LongPtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'l'
+
+class UnsignedLongPtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'L'
+
+class FloatPtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'f'
+
+class DoublePtrExecutor(PtrTypeExecutor):
+    _immutable_ = True
+    typecode = 'd'
+
+
+class ConstructorExecutor(VoidExecutor):
+    _immutable_ = True
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        capi.c_constructor(cppmethod, cppthis, num_args, args)
+        return space.w_None
+
+
+class InstancePtrExecutor(FunctionExecutor):
+    _immutable_ = True
+    libffitype = libffi.types.pointer
+
+    def __init__(self, space, cppclass):
+        FunctionExecutor.__init__(self, space, cppclass)
+        self.cppclass = cppclass
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        from pypy.module.cppyy import interp_cppyy
+        long_result = capi.c_call_l(cppmethod, cppthis, num_args, args)
+        ptr_result = rffi.cast(capi.C_OBJECT, long_result)
+        return interp_cppyy.wrap_cppobject(
+            space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        from pypy.module.cppyy import interp_cppyy
+        ptr_result = rffi.cast(capi.C_OBJECT, libffifunc.call(argchain, rffi.VOIDP))
+        return interp_cppyy.wrap_cppobject(
+            space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
+
+class InstancePtrPtrExecutor(InstancePtrExecutor):
+    _immutable_ = True
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        from pypy.module.cppyy import interp_cppyy
+        voidp_result = capi.c_call_r(cppmethod, cppthis, num_args, args)
+        ref_address = rffi.cast(rffi.VOIDPP, voidp_result)
+        ptr_result = rffi.cast(capi.C_OBJECT, ref_address[0])
+        return interp_cppyy.wrap_cppobject(
+            space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+class InstanceExecutor(InstancePtrExecutor):
+    _immutable_ = True
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        from pypy.module.cppyy import interp_cppyy
+        long_result = capi.c_call_o(cppmethod, cppthis, num_args, args, self.cppclass)
+        ptr_result = rffi.cast(capi.C_OBJECT, long_result)
+        return interp_cppyy.wrap_cppobject(
+            space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=True)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+
+class StdStringExecutor(InstancePtrExecutor):
+    _immutable_ = True
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        charp_result = capi.c_call_s(cppmethod, cppthis, num_args, args)
+        return space.wrap(capi.charp2str_free(charp_result))
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+
+class PyObjectExecutor(PtrTypeExecutor):
+    _immutable_ = True
+
+    def wrap_result(self, space, lresult):
+        space.getbuiltinmodule("cpyext")
+        from pypy.module.cpyext.pyobject import PyObject, from_ref, make_ref, Py_DecRef
+        result = rffi.cast(PyObject, lresult)
+        w_obj = from_ref(space, result)
+        if result:
+            Py_DecRef(space, result)
+        return w_obj
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
+        return self.wrap_result(space, lresult)
+
+    def execute_libffi(self, space, libffifunc, argchain):
+        if hasattr(space, "fake"):
+            raise NotImplementedError
+        lresult = libffifunc.call(argchain, rffi.LONG)
+        return self.wrap_result(space, lresult)
+
+
+_executors = {}
+def get_executor(space, name):
+    # Matching of 'name' to an executor factory goes through up to four levels:
+    #   1) full, qualified match
+    #   2) drop '&': by-ref is pretty much the same as by-value, python-wise
+    #   3) types/classes, either by ref/ptr or by value
+    #   4) additional special cases
+    #
+    # If all fails, a default is used, which can be ignored at least until use.
+
+    name = capi.c_resolve_name(name)
+
+    #   1) full, qualified match
+    try:
+        return _executors[name](space, None)
+    except KeyError:
+        pass
+
+    compound = helper.compound(name)
+    clean_name = helper.clean_type(name)
+
+    #   1a) clean lookup
+    try:
+        return _executors[clean_name+compound](space, None)
+    except KeyError:
+        pass
+
+    #   2) drop '&': by-ref is pretty much the same as by-value, python-wise
+    if compound and compound[len(compound)-1] == "&":
+        # TODO: this does not actually work with Reflex (?)
+        try:
+            return _executors[clean_name](space, None)
+        except KeyError:
+            pass
+
+    #   3) types/classes, either by ref/ptr or by value
+    from pypy.module.cppyy import interp_cppyy
+    cppclass = interp_cppyy.scope_byname(space, clean_name)
+    if cppclass:
+        # type check for the benefit of the annotator
+        from pypy.module.cppyy.interp_cppyy import W_CPPClass
+        cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
+        if compound == "":
+            return InstanceExecutor(space, cppclass)
+        elif compound == "*" or compound == "&":
+            return InstancePtrExecutor(space, cppclass)
+        elif compound == "**" or compound == "*&":
+            return InstancePtrPtrExecutor(space, cppclass)
+    elif capi.c_is_enum(clean_name):
+        return UnsignedIntExecutor(space, None)
+
+    # 4) additional special cases
+    # ... none for now
+
+    # currently used until proper lazy instantiation available in interp_cppyy
+    return FunctionExecutor(space, None)
+ 
+
+_executors["void"]                = VoidExecutor
+_executors["void*"]               = PtrTypeExecutor
+_executors["bool"]                = BoolExecutor
+_executors["char"]                = CharExecutor
+_executors["char*"]               = CStringExecutor
+_executors["unsigned char"]       = CharExecutor
+_executors["short int"]           = ShortExecutor
+_executors["short"]               = _executors["short int"]
+_executors["short int*"]          = ShortPtrExecutor
+_executors["short*"]              = _executors["short int*"]
+_executors["unsigned short int"]  = ShortExecutor
+_executors["unsigned short"]      = _executors["unsigned short int"]
+_executors["unsigned short int*"] = ShortPtrExecutor
+_executors["unsigned short*"]     = _executors["unsigned short int*"]
+_executors["int"]                 = IntExecutor
+_executors["int*"]                = IntPtrExecutor
+_executors["const int&"]          = ConstIntRefExecutor
+_executors["int&"]                = ConstIntRefExecutor
+_executors["unsigned int"]        = UnsignedIntExecutor
+_executors["unsigned int*"]       = UnsignedIntPtrExecutor
+_executors["long int"]            = LongExecutor
+_executors["long"]                = _executors["long int"]
+_executors["long int*"]           = LongPtrExecutor
+_executors["long*"]               = _executors["long int*"]
+_executors["unsigned long int"]   = UnsignedLongExecutor
+_executors["unsigned long"]       = _executors["unsigned long int"]
+_executors["unsigned long int*"]  = UnsignedLongPtrExecutor
+_executors["unsigned long*"]      = _executors["unsigned long int*"]
+_executors["long long int"]       = LongLongExecutor
+_executors["long long"]           = _executors["long long int"]
+_executors["unsigned long long int"] = UnsignedLongLongExecutor
+_executors["unsigned long long"]  = _executors["unsigned long long int"]
+_executors["float"]               = FloatExecutor
+_executors["float*"]              = FloatPtrExecutor
+_executors["double"]              = DoubleExecutor
+_executors["double*"]             = DoublePtrExecutor
+
+_executors["constructor"]         = ConstructorExecutor
+
+# special cases (note: CINT backend requires the simple name 'string')
+_executors["std::basic_string<char>"]        = StdStringExecutor
+_executors["string"]                         = _executors["std::basic_string<char>"]
+
+_executors["PyObject*"]           = PyObjectExecutor
+_executors["_object*"]            = _executors["PyObject*"]
diff --git a/pypy/module/cppyy/genreflex-methptrgetter.patch b/pypy/module/cppyy/genreflex-methptrgetter.patch
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/genreflex-methptrgetter.patch
@@ -0,0 +1,126 @@
+Index: cint/reflex/python/genreflex/gendict.py
+===================================================================
+--- cint/reflex/python/genreflex/gendict.py	(revision 43705)
++++ cint/reflex/python/genreflex/gendict.py	(working copy)
+@@ -52,6 +52,7 @@
+     self.typedefs_for_usr = []
+     self.gccxmlvers = gccxmlvers
+     self.split = opts.get('split', '')
++    self.with_methptrgetter = opts.get('with_methptrgetter', False)
+     # The next is to avoid a known problem with gccxml that it generates a
+     # references to id equal '_0' which is not defined anywhere
+     self.xref['_0'] = {'elem':'Unknown', 'attrs':{'id':'_0','name':''}, 'subelems':[]}
+@@ -1306,6 +1307,8 @@
+     bases = self.getBases( attrs['id'] )
+     if inner and attrs.has_key('demangled') and self.isUnnamedType(attrs['demangled']) :
+       cls = attrs['demangled']
++      if self.xref[attrs['id']]['elem'] == 'Union':
++         return 80*' '
+       clt = ''
+     else:
+       cls = self.genTypeName(attrs['id'],const=True,colon=True)
+@@ -1343,7 +1346,7 @@
+       # Inner class/struct/union/enum.
+       for m in memList :
+         member = self.xref[m]
+-        if member['elem'] in ('Class','Struct','Union','Enumeration') \
++        if member['elem'] in ('Class','Struct','Enumeration') \
+            and member['attrs'].get('access') in ('private','protected') \
+            and not self.isUnnamedType(member['attrs'].get('demangled')):
+           cmem = self.genTypeName(member['attrs']['id'],const=True,colon=True)
+@@ -1981,8 +1984,15 @@
+     else    : params  = '0'
+     s = '  .AddFunctionMember(%s, Reflex::Literal("%s"), %s%s, 0, %s, %s)' % (self.genTypeID(id), name, type, id, params, mod)
+     s += self.genCommentProperty(attrs)
++    s += self.genMethPtrGetterProperty(type, attrs)
+     return s
+ #----------------------------------------------------------------------------------
++  def genMethPtrGetterProperty(self, type, attrs):
++    funcname = self.nameOfMethPtrGetter(type, attrs)
++    if funcname is None:
++      return ''
++    return '\n  .AddProperty("MethPtrGetter", (void*)%s)' % funcname
++#----------------------------------------------------------------------------------
+   def genMCODef(self, type, name, attrs, args):
+     id       = attrs['id']
+     cl       = self.genTypeName(attrs['context'],colon=True)
+@@ -2049,8 +2059,44 @@
+           if returns == 'void' : body += '  }\n'
+           else :                 body += '  }\n'
+     body += '}\n'
+-    return head + body;
++    methptrgetter = self.genMethPtrGetter(type, name, attrs, args)
++    return head + body + methptrgetter
+ #----------------------------------------------------------------------------------
++  def nameOfMethPtrGetter(self, type, attrs):
++    id = attrs['id']
++    if self.with_methptrgetter and 'static' not in attrs and type in ('operator', 'method'):
++      return '%s%s_methptrgetter' % (type, id)
++    return None
++#----------------------------------------------------------------------------------  
++  def genMethPtrGetter(self, type, name, attrs, args):
++    funcname = self.nameOfMethPtrGetter(type, attrs)
++    if funcname is None:
++      return ''
++    id = attrs['id']
++    cl = self.genTypeName(attrs['context'],colon=True)
++    rettype = self.genTypeName(attrs['returns'],enum=True, const=True, colon=True)
++    arg_type_list = [self.genTypeName(arg['type'], colon=True) for arg in args]
++    constness = attrs.get('const', 0) and 'const' or ''
++    lines = []
++    a = lines.append
++    a('static void* %s(void* o)' % (funcname,))
++    a('{')
++    if name == 'EmitVA':
++      # TODO: this is for ROOT TQObject, the problem being that ellipses is not
++      # exposed in the arguments and that makes the generated code fail if the named
++      # method is overloaded as is with TQObject::EmitVA
++      a('  return (void*)0;')
++    else:
++      # declare a variable "meth" which is a member pointer
++      a('  %s (%s::*meth)(%s)%s;' % (rettype, cl, ', '.join(arg_type_list), constness))
++      a('  meth = (%s (%s::*)(%s)%s)&%s::%s;' % \
++         (rettype, cl, ', '.join(arg_type_list), constness, cl, name))
++      a('  %s* obj = (%s*)o;' % (cl, cl))
++      a('  return (void*)(obj->*meth);')
++    a('}')
++    return '\n'.join(lines)
++
++#----------------------------------------------------------------------------------
+   def getDefaultArgs(self, args):
+     n = 0
+     for a in args :
+Index: cint/reflex/python/genreflex/genreflex.py
+===================================================================
+--- cint/reflex/python/genreflex/genreflex.py	(revision 43705)
++++ cint/reflex/python/genreflex/genreflex.py	(working copy)
+@@ -108,6 +108,10 @@
+          Print extra debug information while processing. Keep intermediate files\n
+       --quiet
+          Do not print informational messages\n
++      --with-methptrgetter
++         Add the property MethPtrGetter to every FunctionMember. It contains a pointer to a
++         function which you can call to get the actual function pointer of the method that it's
++         stored in the vtable.  It works only with gcc.
+       -h, --help
+          Print this help\n
+      """ 
+@@ -127,7 +131,8 @@
+       opts, args = getopt.getopt(options, 'ho:s:c:I:U:D:PC', \
+       ['help','debug=', 'output=','selection_file=','pool','dataonly','interpreteronly','deep','gccxmlpath=',
+        'capabilities=','rootmap=','rootmap-lib=','comments','iocomments','no_membertypedefs',
+-       'fail_on_warnings', 'quiet', 'gccxmlopt=', 'reflex', 'split=','no_templatetypedefs','gccxmlpost='])
++       'fail_on_warnings', 'quiet', 'gccxmlopt=', 'reflex', 'split=','no_templatetypedefs','gccxmlpost=',
++       'with-methptrgetter'])
+     except getopt.GetoptError, e:
+       print "--->> genreflex: ERROR:",e
+       self.usage(2)
+@@ -186,6 +191,8 @@
+         self.rootmap = a
+       if o in ('--rootmap-lib',):
+         self.rootmaplib = a
++      if o in ('--with-methptrgetter',):
++        self.opts['with_methptrgetter'] = True
+       if o in ('-I', '-U', '-D', '-P', '-C') :
+         # escape quotes; we need to use " because of windows cmd
+         poseq = a.find('=')
diff --git a/pypy/module/cppyy/helper.py b/pypy/module/cppyy/helper.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/helper.py
@@ -0,0 +1,179 @@
+from pypy.rlib import rstring
+
+
+#- type name manipulations --------------------------------------------------
+def _remove_const(name):
+    return "".join(rstring.split(name, "const")) # poor man's replace
+
+def remove_const(name):
+    return _remove_const(name).strip(' ')
+
+def compound(name):
+    name = _remove_const(name)
+    if name.endswith("]"):                       # array type?
+        return "[]"
+    i = _find_qualifier_index(name)
+    return "".join(name[i:].split(" "))
+
+def array_size(name):
+    name = _remove_const(name)
+    if name.endswith("]"):                       # array type?
+        idx = name.rfind("[")
+        if 0 < idx:
+            end = len(name)-1                    # len rather than -1 for rpython
+            if 0 < end and (idx+1) < end:        # guarantee non-neg for rpython
+                return int(name[idx+1:end])
+    return -1
+
+def _find_qualifier_index(name):
+    i = len(name)
+    # search from the back; note len(name) > 0 (so rtyper can use uint)
+    for i in range(len(name) - 1, 0, -1):
+        c = name[i]
+        if c.isalnum() or c == ">" or c == "]":
+            break
+    return i + 1
+
+def clean_type(name):
+    # can't strip const early b/c name could be a template ...
+    i = _find_qualifier_index(name)
+    name = name[:i].strip(' ')
+
+    idx = -1
+    if name.endswith("]"):                       # array type?
+        idx = name.rfind("[")
+        if 0 < idx:
+             name = name[:idx]
+    elif name.endswith(">"):                     # template type?
+        idx = name.find("<")
+        if 0 < idx:      # always true, but just so that the translater knows
+            n1 = _remove_const(name[:idx])
+            name = "".join([n1, name[idx:]])
+    else:
+        name = _remove_const(name)
+        name = name[:_find_qualifier_index(name)]
+    return name.strip(' ')
+
+
+#- operator mappings --------------------------------------------------------
+_operator_mappings = {}
+
+def map_operator_name(cppname, nargs, result_type):
+    from pypy.module.cppyy import capi
+
+    if cppname[0:8] == "operator":
+        op = cppname[8:].strip(' ')
+
+        # look for known mapping
+        try:
+            return _operator_mappings[op]
+        except KeyError:
+            pass
+
+        # return-type dependent mapping
+        if op == "[]":
+            if result_type.find("const") != 0:
+                cpd = compound(result_type)
+                if cpd and cpd[len(cpd)-1] == "&":
+                    return "__setitem__"
+            return "__getitem__"
+
+        # a couple more cases that depend on whether args were given
+
+        if op == "*":   # dereference (not python) vs. multiplication
+            return nargs and "__mul__" or "__deref__"
+
+        if op == "+":   # unary positive vs. binary addition
+            return nargs and  "__add__" or "__pos__"
+
+        if op == "-":   # unary negative vs. binary subtraction
+            return nargs and "__sub__" or "__neg__"
+
+        if op == "++":  # prefix v.s. postfix increment (not python)
+            return nargs and "__postinc__" or "__preinc__";
+
+        if op == "--":  # prefix v.s. postfix decrement (not python)
+            return nargs and "__postdec__" or "__predec__";
+
+        # operator could have been a conversion using a typedef (this lookup
+        # is put at the end only as it is unlikely and may trigger unwanted
+        # errors in class loaders in the backend, because a typical operator
+        # name is illegal as a class name)
+        true_op = capi.c_resolve_name(op)
+
+        try:
+            return _operator_mappings[true_op]
+        except KeyError:
+            pass
+
+    # might get here, as not all operator methods handled (although some with
+    # no python equivalent, such as new, delete, etc., are simply retained)
+    # TODO: perhaps absorb or "pythonify" these operators?
+    return cppname
+
+# _operator_mappings["[]"]  = "__setitem__"      # depends on return type
+# _operator_mappings["+"]   = "__add__"          # depends on # of args (see __pos__)
+# _operator_mappings["-"]   = "__sub__"          # id. (eq. __neg__)
+# _operator_mappings["*"]   = "__mul__"          # double meaning in C++
+
+# _operator_mappings["[]"]  = "__getitem__"      # depends on return type
+_operator_mappings["()"]  = "__call__"
+_operator_mappings["/"]   = "__div__"            # __truediv__ in p3
+_operator_mappings["%"]   = "__mod__"
+_operator_mappings["**"]  = "__pow__"            # not C++
+_operator_mappings["<<"]  = "__lshift__"
+_operator_mappings[">>"]  = "__rshift__"
+_operator_mappings["&"]   = "__and__"
+_operator_mappings["|"]   = "__or__"
+_operator_mappings["^"]   = "__xor__"
+_operator_mappings["~"]   = "__inv__"
+_operator_mappings["!"]   = "__nonzero__"
+_operator_mappings["+="]  = "__iadd__"
+_operator_mappings["-="]  = "__isub__"
+_operator_mappings["*="]  = "__imul__"
+_operator_mappings["/="]  = "__idiv__"           # __itruediv__ in p3
+_operator_mappings["%="]  = "__imod__"
+_operator_mappings["**="] = "__ipow__"
+_operator_mappings["<<="] = "__ilshift__"
+_operator_mappings[">>="] = "__irshift__"
+_operator_mappings["&="]  = "__iand__"
+_operator_mappings["|="]  = "__ior__"
+_operator_mappings["^="]  = "__ixor__"
+_operator_mappings["=="]  = "__eq__"
+_operator_mappings["!="]  = "__ne__"
+_operator_mappings[">"]   = "__gt__"
+_operator_mappings["<"]   = "__lt__"
+_operator_mappings[">="]  = "__ge__"
+_operator_mappings["<="]  = "__le__"
+
+# the following type mappings are "exact"
+_operator_mappings["const char*"] = "__str__"
+_operator_mappings["int"]         = "__int__"
+_operator_mappings["long"]        = "__long__"   # __int__ in p3
+_operator_mappings["double"]      = "__float__"
+
+# the following type mappings are "okay"; the assumption is that they
+# are not mixed up with the ones above or between themselves (and if
+# they are, that it is done consistently)
+_operator_mappings["char*"]              = "__str__"
+_operator_mappings["short"]              = "__int__"
+_operator_mappings["unsigned short"]     = "__int__"
+_operator_mappings["unsigned int"]       = "__long__"      # __int__ in p3
+_operator_mappings["unsigned long"]      = "__long__"      # id.
+_operator_mappings["long long"]          = "__long__"      # id.
+_operator_mappings["unsigned long long"] = "__long__"      # id.
+_operator_mappings["float"]              = "__float__"
+
+_operator_mappings["bool"] = "__nonzero__"       # __bool__ in p3
+
+# the following are not python, but useful to expose
+_operator_mappings["->"]  = "__follow__"
+_operator_mappings["="]   = "__assign__"
+
+# a bundle of operators that have no equivalent and are left "as-is" for now:
+_operator_mappings["&&"]       = "&&"
+_operator_mappings["||"]       = "||"
+_operator_mappings["new"]      = "new"
+_operator_mappings["delete"]   = "delete"
+_operator_mappings["new[]"]    = "new[]"
+_operator_mappings["delete[]"] = "delete[]"
diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/capi.h
@@ -0,0 +1,111 @@
+#ifndef CPPYY_CAPI
+#define CPPYY_CAPI
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif // ifdef __cplusplus
+
+    typedef long cppyy_scope_t;
+    typedef cppyy_scope_t cppyy_type_t;
+    typedef long cppyy_object_t;
+    typedef long cppyy_method_t;
+    typedef void* (*cppyy_methptrgetter_t)(cppyy_object_t);
+
+    /* name to opaque C++ scope representation -------------------------------- */
+    char* cppyy_resolve_name(const char* cppitem_name);
+    cppyy_scope_t cppyy_get_scope(const char* scope_name);
+    cppyy_type_t cppyy_get_template(const char* template_name);
+    cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj);
+
+    /* memory management ------------------------------------------------------ */
+    cppyy_object_t cppyy_allocate(cppyy_type_t type);
+    void cppyy_deallocate(cppyy_type_t type, cppyy_object_t self);
+    void cppyy_destruct(cppyy_type_t type, cppyy_object_t self);
+
+    /* method/function dispatching -------------------------------------------- */
+    void   cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    int    cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    char   cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    short  cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    int    cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    long   cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+
+    void*  cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    char*  cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+
+    void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, cppyy_type_t result_type);
+
+    cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_scope_t scope, int method_index);
+
+    /* handling of function argument buffer ----------------------------------- */
+    void*  cppyy_allocate_function_args(size_t nargs);
+    void   cppyy_deallocate_function_args(void* args);
+    size_t cppyy_function_arg_sizeof();
+    size_t cppyy_function_arg_typeoffset();
+
+    /* scope reflection information ------------------------------------------- */
+    int cppyy_is_namespace(cppyy_scope_t scope);
+    int cppyy_is_enum(const char* type_name);
+
+    /* class reflection information ------------------------------------------- */
+    char* cppyy_final_name(cppyy_type_t type);
+    char* cppyy_scoped_final_name(cppyy_type_t type);
+    int cppyy_has_complex_hierarchy(cppyy_type_t type);
+    int cppyy_num_bases(cppyy_type_t type);
+    char* cppyy_base_name(cppyy_type_t type, int base_index);
+    int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base);
+
+    /* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */
+    size_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction);
+
+    /* method/function reflection information --------------------------------- */
+    int cppyy_num_methods(cppyy_scope_t scope);
+    char* cppyy_method_name(cppyy_scope_t scope, int method_index);
+    char* cppyy_method_result_type(cppyy_scope_t scope, int method_index);
+    int cppyy_method_num_args(cppyy_scope_t scope, int method_index);
+    int cppyy_method_req_args(cppyy_scope_t scope, int method_index);
+    char* cppyy_method_arg_type(cppyy_scope_t scope, int method_index, int arg_index);
+    char* cppyy_method_arg_default(cppyy_scope_t scope, int method_index, int arg_index);
+    char* cppyy_method_signature(cppyy_scope_t scope, int method_index);
+
+    int cppyy_method_index(cppyy_scope_t scope, const char* name);
+
+    cppyy_method_t cppyy_get_method(cppyy_scope_t scope, int method_index);
+
+    /* method properties -----------------------------------------------------  */
+    int cppyy_is_constructor(cppyy_type_t type, int method_index);
+    int cppyy_is_staticmethod(cppyy_type_t type, int method_index);
+
+    /* data member reflection information ------------------------------------  */
+    int cppyy_num_datamembers(cppyy_scope_t scope);
+    char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index);
+    char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index);
+    size_t cppyy_datamember_offset(cppyy_scope_t scope, int datamember_index);
+
+    int cppyy_datamember_index(cppyy_scope_t scope, const char* name);
+
+    /* data member properties ------------------------------------------------  */
+    int cppyy_is_publicdata(cppyy_type_t type, int datamember_index);
+    int cppyy_is_staticdata(cppyy_type_t type, int datamember_index);
+
+    /* misc helpers ----------------------------------------------------------- */
+    void cppyy_free(void* ptr);
+    long long cppyy_strtoll(const char* str);
+    unsigned long long cppyy_strtuoll(const char* str);
+
+    cppyy_object_t cppyy_charp2stdstring(const char* str);
+    cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr);
+    void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str);
+    void cppyy_free_stdstring(cppyy_object_t ptr);
+
+#ifdef __cplusplus
+}
+#endif // ifdef __cplusplus
+
+#endif // ifndef CPPYY_CAPI
diff --git a/pypy/module/cppyy/include/cintcwrapper.h b/pypy/module/cppyy/include/cintcwrapper.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/cintcwrapper.h
@@ -0,0 +1,16 @@
+#ifndef CPPYY_CINTCWRAPPER
+#define CPPYY_CINTCWRAPPER
+
+#include "capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // ifdef __cplusplus
+
+    void* cppyy_load_dictionary(const char* lib_name);
+
+#ifdef __cplusplus
+}
+#endif // ifdef __cplusplus
+
+#endif // ifndef CPPYY_CINTCWRAPPER
diff --git a/pypy/module/cppyy/include/cppyy.h b/pypy/module/cppyy/include/cppyy.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/cppyy.h
@@ -0,0 +1,64 @@
+#ifndef CPPYY_CPPYY
+#define CPPYY_CPPYY
+
+#ifdef __cplusplus
+struct CPPYY_G__DUMMY_FOR_CINT7 {
+#else
+typedef struct
+#endif
+   void* fTypeName;
+   unsigned int fModifiers;
+#ifdef __cplusplus
+};
+#else
+} CPPYY_G__DUMMY_FOR_CINT7;
+#endif
+
+#ifdef __cplusplus
+struct CPPYY_G__p2p {
+#else
+#typedef struct
+#endif
+  long i;
+  int reftype;
+#ifdef __cplusplus
+};
+#else
+} CPPYY_G__p2p;
+#endif
+
+
+#ifdef __cplusplus
+struct CPPYY_G__value {
+#else
+typedef struct {
+#endif
+  union {
+    double d;
+    long    i; /* used to be int */
+    struct CPPYY_G__p2p reftype;
+    char ch;
+    short sh;
+    int in;
+    float fl;
+    unsigned char uch;
+    unsigned short ush;
+    unsigned int uin;
+    unsigned long ulo;
+    long long ll;
+    unsigned long long ull;
+    long double ld;
+  } obj;
+  long ref;
+  int type;
+  int tagnum;
+  int typenum;
+  char isconst;
+  struct CPPYY_G__DUMMY_FOR_CINT7 dummyForCint7;
+#ifdef __cplusplus
+};
+#else
+} CPPYY_G__value;
+#endif
+
+#endif // CPPYY_CPPYY
diff --git a/pypy/module/cppyy/include/reflexcwrapper.h b/pypy/module/cppyy/include/reflexcwrapper.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/reflexcwrapper.h
@@ -0,0 +1,6 @@
+#ifndef CPPYY_REFLEXCWRAPPER
+#define CPPYY_REFLEXCWRAPPER
+
+#include "capi.h"
+
+#endif // ifndef CPPYY_REFLEXCWRAPPER
diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -0,0 +1,807 @@
+import pypy.module.cppyy.capi as capi
+
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
+from pypy.interpreter.baseobjspace import Wrappable, W_Root
+
+from pypy.rpython.lltypesystem import rffi, lltype
+
+from pypy.rlib import libffi, rdynload, rweakref
+from pypy.rlib import jit, debug, objectmodel
+
+from pypy.module.cppyy import converter, executor, helper
+
+
+class FastCallNotPossible(Exception):
+    pass
+
+
+ at unwrap_spec(name=str)
+def load_dictionary(space, name):
+    try:
+        cdll = capi.c_load_dictionary(name)
+    except rdynload.DLOpenError, e:
+        raise OperationError(space.w_RuntimeError, space.wrap(str(e)))
+    return W_CPPLibrary(space, cdll)
+
+class State(object):
+    def __init__(self, space):
+        self.cppscope_cache = {
+            "void" : W_CPPClass(space, "void", capi.C_NULL_TYPE) }
+        self.cpptemplate_cache = {}
+        self.cppclass_registry = {}
+        self.w_clgen_callback = None
+
+ at unwrap_spec(name=str)
+def resolve_name(space, name):
+    return space.wrap(capi.c_resolve_name(name))
+
+ at unwrap_spec(name=str)
+def scope_byname(space, name):
+    true_name = capi.c_resolve_name(name)
+
+    state = space.fromcache(State)
+    try:
+        return state.cppscope_cache[true_name]
+    except KeyError:
+        pass
+
+    opaque_handle = capi.c_get_scope_opaque(true_name)
+    assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
+    if opaque_handle:
+        final_name = capi.c_final_name(opaque_handle)
+        if capi.c_is_namespace(opaque_handle):
+            cppscope = W_CPPNamespace(space, final_name, opaque_handle)
+        elif capi.c_has_complex_hierarchy(opaque_handle):
+            cppscope = W_ComplexCPPClass(space, final_name, opaque_handle)
+        else:
+            cppscope = W_CPPClass(space, final_name, opaque_handle)
+        state.cppscope_cache[name] = cppscope
+
+        cppscope._find_methods()
+        cppscope._find_datamembers()
+        return cppscope
+
+    return None
+
+ at unwrap_spec(name=str)
+def template_byname(space, name):
+    state = space.fromcache(State)
+    try:
+        return state.cpptemplate_cache[name]
+    except KeyError:
+        pass
+
+    opaque_handle = capi.c_get_template(name)
+    assert lltype.typeOf(opaque_handle) == capi.C_TYPE
+    if opaque_handle:
+        cpptemplate = W_CPPTemplateType(space, name, opaque_handle)
+        state.cpptemplate_cache[name] = cpptemplate
+        return cpptemplate
+
+    return None
+
+ at unwrap_spec(w_callback=W_Root)
+def set_class_generator(space, w_callback):
+    state = space.fromcache(State)
+    state.w_clgen_callback = w_callback
+
+ at unwrap_spec(w_pycppclass=W_Root)
+def register_class(space, w_pycppclass):
+    w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
+    cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+    state = space.fromcache(State)
+    state.cppclass_registry[cppclass.handle] = w_pycppclass
+
+
+class W_CPPLibrary(Wrappable):
+    _immutable_ = True
+
+    def __init__(self, space, cdll):
+        self.cdll = cdll
+        self.space = space
+
+W_CPPLibrary.typedef = TypeDef(
+    'CPPLibrary',
+)
+W_CPPLibrary.typedef.acceptable_as_base_class = True
+
+
+class CPPMethod(object):
+    """ A concrete function after overloading has been resolved """
+    _immutable_ = True
+    
+    def __init__(self, space, containing_scope, method_index, arg_defs, args_required):
+        self.space = space
+        self.scope = containing_scope
+        self.index = method_index
+        self.cppmethod = capi.c_get_method(self.scope, method_index)
+        self.arg_defs = arg_defs
+        self.args_required = args_required
+        self.args_expected = len(arg_defs)
+
+        # Setup of the method dispatch's innards is done lazily, i.e. only when
+        # the method is actually used.
+        self.converters = None
+        self.executor = None
+        self._libffifunc = None
+
+    def _address_from_local_buffer(self, call_local, idx):
+        if not call_local:
+            return call_local
+        stride = 2*rffi.sizeof(rffi.VOIDP)
+        loc_idx = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, call_local), idx*stride)
+        return rffi.cast(rffi.VOIDP, loc_idx)
+
+    @jit.unroll_safe
+    def call(self, cppthis, args_w):
+        jit.promote(self)
+        assert lltype.typeOf(cppthis) == capi.C_OBJECT
+
+        # check number of given arguments against required (== total - defaults)
+        args_expected = len(self.arg_defs)
+        args_given = len(args_w)
+        if args_expected < args_given or args_given < self.args_required:
+            raise OperationError(self.space.w_TypeError,
+                                 self.space.wrap("wrong number of arguments"))
+
+        # initial setup of converters, executors, and libffi (if available)
+        if self.converters is None:
+            self._setup(cppthis)
+
+        # some calls, e.g. for ptr-ptr or reference need a local array to store data for
+        # the duration of the call
+        if [conv for conv in self.converters if conv.uses_local]:
+            call_local = lltype.malloc(rffi.VOIDP.TO, 2*len(args_w), flavor='raw')
+        else:
+            call_local = lltype.nullptr(rffi.VOIDP.TO)
+
+        try:
+            # attempt to call directly through ffi chain
+            if self._libffifunc:
+                try:
+                    return self.do_fast_call(cppthis, args_w, call_local)
+                except FastCallNotPossible:
+                    pass      # can happen if converters or executor does not implement ffi
+
+            # ffi chain must have failed; using stub functions instead
+            args = self.prepare_arguments(args_w, call_local)
+            try:
+                return self.executor.execute(self.space, self.cppmethod, cppthis, len(args_w), args)
+            finally:
+                self.finalize_call(args, args_w, call_local)
+        finally:
+            if call_local:
+                lltype.free(call_local, flavor='raw')
+
+    @jit.unroll_safe
+    def do_fast_call(self, cppthis, args_w, call_local):
+        jit.promote(self)
+        argchain = libffi.ArgChain()
+        argchain.arg(cppthis)
+        i = len(self.arg_defs)
+        for i in range(len(args_w)):
+            conv = self.converters[i]
+            w_arg = args_w[i]
+            conv.convert_argument_libffi(self.space, w_arg, argchain, call_local)
+        for j in range(i+1, len(self.arg_defs)):
+            conv = self.converters[j]
+            conv.default_argument_libffi(self.space, argchain)
+        return self.executor.execute_libffi(self.space, self._libffifunc, argchain)
+
+    def _setup(self, cppthis):
+        self.converters = [converter.get_converter(self.space, arg_type, arg_dflt)
+                               for arg_type, arg_dflt in self.arg_defs]
+        self.executor = executor.get_executor(self.space, capi.c_method_result_type(self.scope, self.index))
+
+        # Each CPPMethod corresponds one-to-one to a C++ equivalent and cppthis
+        # has been offset to the matching class. Hence, the libffi pointer is
+        # uniquely defined and needs to be setup only once.
+        methgetter = capi.c_get_methptr_getter(self.scope, self.index)
+        if methgetter and cppthis:      # methods only for now
+            funcptr = methgetter(rffi.cast(capi.C_OBJECT, cppthis))
+            argtypes_libffi = [conv.libffitype for conv in self.converters if conv.libffitype]
+            if (len(argtypes_libffi) == len(self.converters) and
+                    self.executor.libffitype):
+                # add c++ this to the arguments
+                libffifunc = libffi.Func("XXX",
+                                         [libffi.types.pointer] + argtypes_libffi,
+                                         self.executor.libffitype, funcptr)
+                self._libffifunc = libffifunc
+
+    @jit.unroll_safe
+    def prepare_arguments(self, args_w, call_local):
+        jit.promote(self)
+        args = capi.c_allocate_function_args(len(args_w))
+        stride = capi.c_function_arg_sizeof()
+        for i in range(len(args_w)):
+            conv = self.converters[i]
+            w_arg = args_w[i]
+            try:
+                arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
+                loc_i = self._address_from_local_buffer(call_local, i)
+                conv.convert_argument(self.space, w_arg, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
+            except:
+                # fun :-(
+                for j in range(i):
+                    conv = self.converters[j]
+                    arg_j = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), j*stride)
+                    loc_j = self._address_from_local_buffer(call_local, j)
+                    conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_j), loc_j)
+                capi.c_deallocate_function_args(args)
+                raise
+        return args
+
+    @jit.unroll_safe
+    def finalize_call(self, args, args_w, call_local):
+        stride = capi.c_function_arg_sizeof()
+        for i in range(len(args_w)):
+            conv = self.converters[i]
+            arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
+            loc_i = self._address_from_local_buffer(call_local, i)
+            conv.finalize_call(self.space, args_w[i], loc_i)
+            conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
+        capi.c_deallocate_function_args(args)
+
+    def signature(self):
+        return capi.c_method_signature(self.scope, self.index)
+
+    def __repr__(self):
+        return "CPPMethod: %s" % self.signature()
+
+    def _freeze_(self):
+        assert 0, "you should never have a pre-built instance of this!"
+
+
+class CPPFunction(CPPMethod):
+    _immutable_ = True
+
+    def __repr__(self):
+        return "CPPFunction: %s" % self.signature()
+
+
+class CPPConstructor(CPPMethod):
+    _immutable_ = True
+
+    def call(self, cppthis, args_w):
+        newthis = capi.c_allocate(self.scope)
+        assert lltype.typeOf(newthis) == capi.C_OBJECT
+        try:
+            CPPMethod.call(self, newthis, args_w)
+        except:
+            capi.c_deallocate(self.scope, newthis)
+            raise
+        return wrap_new_cppobject_nocast(
+            self.space, self.space.w_None, self.scope, newthis, isref=False, python_owns=True)
+
+    def __repr__(self):
+        return "CPPConstructor: %s" % self.signature()
+
+
+class W_CPPOverload(Wrappable):
+    _immutable_ = True
+
+    def __init__(self, space, containing_scope, functions):
+        self.space = space
+        self.scope = containing_scope
+        self.functions = debug.make_sure_not_resized(functions)
+
+    def is_static(self):
+        return self.space.wrap(isinstance(self.functions[0], CPPFunction))
+
+    @jit.unroll_safe
+    @unwrap_spec(args_w='args_w')
+    def call(self, w_cppinstance, args_w):
+        cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+        if cppinstance is not None:
+            cppinstance._nullcheck()
+            cppthis = cppinstance.get_cppthis(self.scope)
+        else:
+            cppthis = capi.C_NULL_OBJECT
+        assert lltype.typeOf(cppthis) == capi.C_OBJECT
+
+        # The following code tries out each of the functions in order. If
+        # argument conversion fails (or simply if the number of arguments do
+        # not match, that will lead to an exception, The JIT will snip out
+        # those (always) failing paths, but only if they have no side-effects.
+        # A second loop gathers all exceptions in the case all methods fail
+        # (the exception gathering would otherwise be a side-effect as far as
+        # the JIT is concerned).
+        #
+        # TODO: figure out what happens if a callback into from the C++ call
+        # raises a Python exception.
+        jit.promote(self)
+        for i in range(len(self.functions)):
+            cppyyfunc = self.functions[i]
+            try:
+                return cppyyfunc.call(cppthis, args_w)
+            except Exception:
+                pass
+
+        # only get here if all overloads failed ...
+        errmsg = 'none of the %d overloaded methods succeeded. Full details:' % len(self.functions)
+        if hasattr(self.space, "fake"):     # FakeSpace fails errorstr (see below)
+            raise OperationError(self.space.w_TypeError, self.space.wrap(errmsg))
+        for i in range(len(self.functions)):
+            cppyyfunc = self.functions[i]
+            try:
+                return cppyyfunc.call(cppthis, args_w)
+            except OperationError, e:
+                errmsg += '\n  '+cppyyfunc.signature()+' =>\n'
+                errmsg += '    '+e.errorstr(self.space)
+            except Exception, e:
+                errmsg += '\n  '+cppyyfunc.signature()+' =>\n'
+                errmsg += '    Exception: '+str(e)
+
+        raise OperationError(self.space.w_TypeError, self.space.wrap(errmsg))
+
+    def signature(self):
+        sig = self.functions[0].signature()
+        for i in range(1, len(self.functions)):
+            sig += '\n'+self.functions[i].signature()
+        return self.space.wrap(sig)
+
+    def __repr__(self):
+        return "W_CPPOverload(%s)" % [f.signature() for f in self.functions]
+
+W_CPPOverload.typedef = TypeDef(
+    'CPPOverload',
+    is_static = interp2app(W_CPPOverload.is_static),
+    call = interp2app(W_CPPOverload.call),
+    signature = interp2app(W_CPPOverload.signature),
+)
+
+
+class W_CPPDataMember(Wrappable):
+    _immutable_ = True
+
+    def __init__(self, space, containing_scope, type_name, offset, is_static):
+        self.space = space
+        self.scope = containing_scope
+        self.converter = converter.get_converter(self.space, type_name, '')
+        self.offset = offset
+        self._is_static = is_static
+
+    def get_returntype(self):
+        return self.space.wrap(self.converter.name)
+
+    def is_static(self):
+        return self.space.newbool(self._is_static)
+
+    @jit.elidable_promote()
+    def _get_offset(self, cppinstance):
+        if cppinstance:
+            assert lltype.typeOf(cppinstance.cppclass.handle) == lltype.typeOf(self.scope.handle)
+            offset = self.offset + capi.c_base_offset(
+                cppinstance.cppclass, self.scope, cppinstance.get_rawobject(), 1)
+        else:
+            offset = self.offset
+        return offset
+
+    def get(self, w_cppinstance, w_pycppclass):
+        cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+        offset = self._get_offset(cppinstance)
+        return self.converter.from_memory(self.space, w_cppinstance, w_pycppclass, offset)
+
+    def set(self, w_cppinstance, w_value):
+        cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+        offset = self._get_offset(cppinstance)
+        self.converter.to_memory(self.space, w_cppinstance, w_value, offset)
+        return self.space.w_None
+
+W_CPPDataMember.typedef = TypeDef(
+    'CPPDataMember',
+    is_static = interp2app(W_CPPDataMember.is_static),
+    get_returntype = interp2app(W_CPPDataMember.get_returntype),
+    get = interp2app(W_CPPDataMember.get),
+    set = interp2app(W_CPPDataMember.set),
+)
+W_CPPDataMember.typedef.acceptable_as_base_class = False
+
+
+class W_CPPScope(Wrappable):
+    _immutable_ = True
+    _immutable_fields_ = ["methods[*]", "datamembers[*]"]
+
+    kind = "scope"
+
+    def __init__(self, space, name, opaque_handle):
+        self.space = space
+        self.name = name
+        assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
+        self.handle = opaque_handle
+        self.methods = {}
+        # Do not call "self._find_methods()" here, so that a distinction can
+        #  be made between testing for existence (i.e. existence in the cache
+        #  of classes) and actual use. Point being that a class can use itself,
+        #  e.g. as a return type or an argument to one of its methods.
+
+        self.datamembers = {}
+        # Idem self.methods: a type could hold itself by pointer.
+
+    def _find_methods(self):
+        num_methods = capi.c_num_methods(self)
+        args_temp = {}
+        for i in range(num_methods):
+            method_name = capi.c_method_name(self, i)
+            pymethod_name = helper.map_operator_name(
+                    method_name, capi.c_method_num_args(self, i),
+                    capi.c_method_result_type(self, i))
+            if not pymethod_name in self.methods:
+                cppfunction = self._make_cppfunction(i)
+                overload = args_temp.setdefault(pymethod_name, [])
+                overload.append(cppfunction)
+        for name, functions in args_temp.iteritems():
+            overload = W_CPPOverload(self.space, self, functions[:])
+            self.methods[name] = overload
+
+    def get_method_names(self):
+        return self.space.newlist([self.space.wrap(name) for name in self.methods])
+
+    @jit.elidable_promote('0')
+    def get_overload(self, name):
+        try:
+            return self.methods[name]
+        except KeyError:
+            pass
+        new_method = self.find_overload(name)
+        self.methods[name] = new_method
+        return new_method
+
+    def get_datamember_names(self):
+        return self.space.newlist([self.space.wrap(name) for name in self.datamembers])
+
+    @jit.elidable_promote('0')
+    def get_datamember(self, name):
+        try:
+            return self.datamembers[name]
+        except KeyError:
+            pass
+        new_dm = self.find_datamember(name)
+        self.datamembers[name] = new_dm
+        return new_dm
+
+    @jit.elidable_promote('0')
+    def dispatch(self, name, signature):
+        overload = self.get_overload(name)
+        sig = '(%s)' % signature
+        for f in overload.functions:
+            if 0 < f.signature().find(sig):
+                return W_CPPOverload(self.space, self, [f])
+        raise OperationError(self.space.w_TypeError, self.space.wrap("no overload matches signature"))
+
+    def missing_attribute_error(self, name):
+        return OperationError(
+            self.space.w_AttributeError,
+            self.space.wrap("%s '%s' has no attribute %s" % (self.kind, self.name, name)))
+
+    def __eq__(self, other):
+        return self.handle == other.handle
+
+
+# For now, keep namespaces and classes separate as namespaces are extensible
+# with info from multiple dictionaries and do not need to bother with meta
+# classes for inheritance. Both are python classes, though, and refactoring
+# may be in order at some point.
+class W_CPPNamespace(W_CPPScope):
+    _immutable_ = True
+    kind = "namespace"
+
+    def _make_cppfunction(self, method_index):
+        num_args = capi.c_method_num_args(self, method_index)
+        args_required = capi.c_method_req_args(self, method_index)
+        arg_defs = []
+        for i in range(num_args):
+            arg_type = capi.c_method_arg_type(self, method_index, i)
+            arg_dflt = capi.c_method_arg_default(self, method_index, i)
+            arg_defs.append((arg_type, arg_dflt))
+        return CPPFunction(self.space, self, method_index, arg_defs, args_required)
+
+    def _make_datamember(self, dm_name, dm_idx):
+        type_name = capi.c_datamember_type(self, dm_idx)
+        offset = capi.c_datamember_offset(self, dm_idx)
+        datamember = W_CPPDataMember(self.space, self, type_name, offset, True)
+        self.datamembers[dm_name] = datamember
+        return datamember
+
+    def _find_datamembers(self):
+        num_datamembers = capi.c_num_datamembers(self)
+        for i in range(num_datamembers):
+            if not capi.c_is_publicdata(self, i):
+                continue
+            datamember_name = capi.c_datamember_name(self, i)
+            if not datamember_name in self.datamembers:
+                self._make_datamember(datamember_name, i)
+
+    def find_overload(self, meth_name):
+        # TODO: collect all overloads, not just the non-overloaded version
+        meth_idx = capi.c_method_index(self, meth_name)
+        if meth_idx < 0:
+            raise self.missing_attribute_error(meth_name)
+        cppfunction = self._make_cppfunction(meth_idx)
+        overload = W_CPPOverload(self.space, self, [cppfunction])
+        return overload
+
+    def find_datamember(self, dm_name):
+        dm_idx = capi.c_datamember_index(self, dm_name)
+        if dm_idx < 0:
+            raise self.missing_attribute_error(dm_name)
+        datamember = self._make_datamember(dm_name, dm_idx)
+        return datamember
+
+    def update(self):
+        self._find_methods()
+        self._find_datamembers()
+
+    def is_namespace(self):
+        return self.space.w_True
+
+W_CPPNamespace.typedef = TypeDef(
+    'CPPNamespace',
+    update = interp2app(W_CPPNamespace.update),
+    get_method_names = interp2app(W_CPPNamespace.get_method_names),
+    get_overload = interp2app(W_CPPNamespace.get_overload, unwrap_spec=['self', str]),
+    get_datamember_names = interp2app(W_CPPNamespace.get_datamember_names),
+    get_datamember = interp2app(W_CPPNamespace.get_datamember, unwrap_spec=['self', str]),
+    is_namespace = interp2app(W_CPPNamespace.is_namespace),
+)
+W_CPPNamespace.typedef.acceptable_as_base_class = False
+
+
+class W_CPPClass(W_CPPScope):
+    _immutable_ = True
+    kind = "class"
+
+    def _make_cppfunction(self, method_index):
+        num_args = capi.c_method_num_args(self, method_index)
+        args_required = capi.c_method_req_args(self, method_index)
+        arg_defs = []
+        for i in range(num_args):
+            arg_type = capi.c_method_arg_type(self, method_index, i)
+            arg_dflt = capi.c_method_arg_default(self, method_index, i)
+            arg_defs.append((arg_type, arg_dflt))
+        if capi.c_is_constructor(self, method_index):
+            cls = CPPConstructor
+        elif capi.c_is_staticmethod(self, method_index):
+            cls = CPPFunction
+        else:
+            cls = CPPMethod
+        return cls(self.space, self, method_index, arg_defs, args_required)
+
+    def _find_datamembers(self):
+        num_datamembers = capi.c_num_datamembers(self)
+        for i in range(num_datamembers):
+            if not capi.c_is_publicdata(self, i):
+                continue
+            datamember_name = capi.c_datamember_name(self, i)
+            type_name = capi.c_datamember_type(self, i)
+            offset = capi.c_datamember_offset(self, i)
+            is_static = bool(capi.c_is_staticdata(self, i))
+            datamember = W_CPPDataMember(self.space, self, type_name, offset, is_static)
+            self.datamembers[datamember_name] = datamember
+
+    def find_overload(self, name):
+        raise self.missing_attribute_error(name)
+
+    def find_datamember(self, name):
+        raise self.missing_attribute_error(name)
+
+    def get_cppthis(self, cppinstance, calling_scope):
+        assert self == cppinstance.cppclass
+        return cppinstance.get_rawobject()
+
+    def is_namespace(self):
+        return self.space.w_False
+
+    def get_base_names(self):
+        bases = []
+        num_bases = capi.c_num_bases(self)
+        for i in range(num_bases):
+            base_name = capi.c_base_name(self, i)
+            bases.append(self.space.wrap(base_name))
+        return self.space.newlist(bases)
+
+W_CPPClass.typedef = TypeDef(
+    'CPPClass',
+    type_name = interp_attrproperty('name', W_CPPClass),
+    get_base_names = interp2app(W_CPPClass.get_base_names),
+    get_method_names = interp2app(W_CPPClass.get_method_names),
+    get_overload = interp2app(W_CPPClass.get_overload, unwrap_spec=['self', str]),
+    get_datamember_names = interp2app(W_CPPClass.get_datamember_names),
+    get_datamember = interp2app(W_CPPClass.get_datamember, unwrap_spec=['self', str]),
+    is_namespace = interp2app(W_CPPClass.is_namespace),
+    dispatch = interp2app(W_CPPClass.dispatch, unwrap_spec=['self', str, str])
+)
+W_CPPClass.typedef.acceptable_as_base_class = False
+
+
+class W_ComplexCPPClass(W_CPPClass):
+    _immutable_ = True
+
+    def get_cppthis(self, cppinstance, calling_scope):
+        assert self == cppinstance.cppclass
+        offset = capi.c_base_offset(self, calling_scope, cppinstance.get_rawobject(), 1)
+        return capi.direct_ptradd(cppinstance.get_rawobject(), offset)
+
+W_ComplexCPPClass.typedef = TypeDef(
+    'ComplexCPPClass',
+    type_name = interp_attrproperty('name', W_CPPClass),
+    get_base_names = interp2app(W_ComplexCPPClass.get_base_names),
+    get_method_names = interp2app(W_ComplexCPPClass.get_method_names),
+    get_overload = interp2app(W_ComplexCPPClass.get_overload, unwrap_spec=['self', str]),
+    get_datamember_names = interp2app(W_ComplexCPPClass.get_datamember_names),
+    get_datamember = interp2app(W_ComplexCPPClass.get_datamember, unwrap_spec=['self', str]),
+    is_namespace = interp2app(W_ComplexCPPClass.is_namespace),
+    dispatch = interp2app(W_CPPClass.dispatch, unwrap_spec=['self', str, str])
+)
+W_ComplexCPPClass.typedef.acceptable_as_base_class = False
+
+
+class W_CPPTemplateType(Wrappable):
+    _immutable_ = True
+
+    def __init__(self, space, name, opaque_handle):
+        self.space = space
+        self.name = name
+        assert lltype.typeOf(opaque_handle) == capi.C_TYPE
+        self.handle = opaque_handle
+
+    @unwrap_spec(args_w='args_w')
+    def __call__(self, args_w):
+        # TODO: this is broken but unused (see pythonify.py)
+        fullname = "".join([self.name, '<', self.space.str_w(args_w[0]), '>'])
+        return scope_byname(self.space, fullname)
+
+W_CPPTemplateType.typedef = TypeDef(
+    'CPPTemplateType',
+    __call__ = interp2app(W_CPPTemplateType.__call__),
+)
+W_CPPTemplateType.typedef.acceptable_as_base_class = False
+
+
+class W_CPPInstance(Wrappable):
+    _immutable_fields_ = ["cppclass", "isref"]
+
+    def __init__(self, space, cppclass, rawobject, isref, python_owns):
+        self.space = space
+        self.cppclass = cppclass
+        assert lltype.typeOf(rawobject) == capi.C_OBJECT
+        assert not isref or rawobject
+        self._rawobject = rawobject
+        assert not isref or not python_owns
+        self.isref = isref
+        self.python_owns = python_owns
+
+    def _nullcheck(self):
+        if not self._rawobject or (self.isref and not self.get_rawobject()):
+            raise OperationError(self.space.w_ReferenceError,
+                                 self.space.wrap("trying to access a NULL pointer"))
+
+    # allow user to determine ownership rules on a per object level
+    def fget_python_owns(self, space):
+        return space.wrap(self.python_owns)
+
+    @unwrap_spec(value=bool)
+    def fset_python_owns(self, space, value):
+        self.python_owns = space.is_true(value)
+
+    def get_cppthis(self, calling_scope):
+        return self.cppclass.get_cppthis(self, calling_scope)
+
+    def get_rawobject(self):
+        if not self.isref:
+            return self._rawobject
+        else:
+            ptrptr = rffi.cast(rffi.VOIDPP, self._rawobject)
+            return rffi.cast(capi.C_OBJECT, ptrptr[0])
+
+    def instance__eq__(self, w_other):
+        other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False)
+        iseq = self._rawobject == other._rawobject
+        return self.space.wrap(iseq)
+
+    def instance__ne__(self, w_other):
+        return self.space.not_(self.instance__eq__(w_other))
+
+    def instance__nonzero__(self):
+        if not self._rawobject or (self.isref and not self.get_rawobject()):
+            return self.space.w_False
+        return self.space.w_True
+
+    def destruct(self):
+        assert isinstance(self, W_CPPInstance)
+        if self._rawobject and not self.isref:
+            memory_regulator.unregister(self)
+            capi.c_destruct(self.cppclass, self._rawobject)
+            self._rawobject = capi.C_NULL_OBJECT
+
+    def __del__(self):
+        if self.python_owns:
+            self.enqueue_for_destruction(self.space, W_CPPInstance.destruct,
+                                         '__del__() method of ')
+
+W_CPPInstance.typedef = TypeDef(
+    'CPPInstance',
+    cppclass = interp_attrproperty('cppclass', cls=W_CPPInstance),
+    _python_owns = GetSetProperty(W_CPPInstance.fget_python_owns, W_CPPInstance.fset_python_owns),
+    __eq__ = interp2app(W_CPPInstance.instance__eq__),
+    __ne__ = interp2app(W_CPPInstance.instance__ne__),
+    __nonzero__ = interp2app(W_CPPInstance.instance__nonzero__),
+    destruct = interp2app(W_CPPInstance.destruct),
+)
+W_CPPInstance.typedef.acceptable_as_base_class = True
+
+
+class MemoryRegulator:
+    # TODO: (?) An object address is not unique if e.g. the class has a
+    # public data member of class type at the start of its definition and
+    # has no virtual functions. A _key class that hashes on address and
+    # type would be better, but my attempt failed in the rtyper, claiming
+    # a call on None ("None()") and needed a default ctor. (??)
+    # Note that for now, the associated test carries an m_padding to make
+    # a difference in the addresses.
+    def __init__(self):
+        self.objects = rweakref.RWeakValueDictionary(int, W_CPPInstance)
+
+    def register(self, obj):
+        int_address = int(rffi.cast(rffi.LONG, obj._rawobject))
+        self.objects.set(int_address, obj)
+
+    def unregister(self, obj):
+        int_address = int(rffi.cast(rffi.LONG, obj._rawobject))
+        self.objects.set(int_address, None)
+
+    def retrieve(self, address):
+        int_address = int(rffi.cast(rffi.LONG, address))
+        return self.objects.get(int_address)
+
+memory_regulator = MemoryRegulator()
+
+
+def get_pythonized_cppclass(space, handle):
+    state = space.fromcache(State)
+    try:
+        w_pycppclass = state.cppclass_registry[handle]
+    except KeyError:
+        final_name = capi.c_scoped_final_name(handle)
+        w_pycppclass = space.call_function(state.w_clgen_callback, space.wrap(final_name))
+    return w_pycppclass
+
+def wrap_new_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+    if space.is_w(w_pycppclass, space.w_None):
+        w_pycppclass = get_pythonized_cppclass(space, cppclass.handle)
+    w_cppinstance = space.allocate_instance(W_CPPInstance, w_pycppclass)
+    cppinstance = space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=False)
+    W_CPPInstance.__init__(cppinstance, space, cppclass, rawobject, isref, python_owns)
+    memory_regulator.register(cppinstance)
+    return w_cppinstance
+
+def wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+    obj = memory_regulator.retrieve(rawobject)
+    if obj and obj.cppclass == cppclass:
+        return obj
+    return wrap_new_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns)
+
+def wrap_cppobject(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+    if rawobject:
+        actual = capi.c_actual_class(cppclass, rawobject)
+        if actual != cppclass.handle:
+            offset = capi._c_base_offset(actual, cppclass.handle, rawobject, -1)
+            rawobject = capi.direct_ptradd(rawobject, offset)
+            w_pycppclass = get_pythonized_cppclass(space, actual)
+            w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
+            cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+    return wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns)
+
+ at unwrap_spec(cppinstance=W_CPPInstance)
+def addressof(space, cppinstance):
+     address = rffi.cast(rffi.LONG, cppinstance.get_rawobject())
+     return space.wrap(address)
+
+ at unwrap_spec(address=int, owns=bool)
+def bind_object(space, address, w_pycppclass, owns=False):
+    rawobject = rffi.cast(capi.C_OBJECT, address)
+    w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
+    cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+    return wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, False, owns)
diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/pythonify.py
@@ -0,0 +1,388 @@
+# NOT_RPYTHON
+import cppyy
+import types
+
+
+# For now, keep namespaces and classes separate as namespaces are extensible
+# with info from multiple dictionaries and do not need to bother with meta
+# classes for inheritance. Both are python classes, though, and refactoring
+# may be in order at some point.
+class CppyyScopeMeta(type):
+    def __getattr__(self, name):
+        try:
+            return get_pycppitem(self, name)  # will cache on self
+        except TypeError, t:
+            raise AttributeError("%s object has no attribute '%s'" % (self, name))
+
+class CppyyNamespaceMeta(CppyyScopeMeta):
+    pass
+
+class CppyyClass(CppyyScopeMeta):
+    pass
+
+class CPPObject(cppyy.CPPInstance):
+    __metaclass__ = CppyyClass
+
+
+class CppyyTemplateType(object):
+    def __init__(self, scope, name):
+        self._scope = scope
+        self._name = name
+
+    def _arg_to_str(self, arg):
+        if type(arg) != str:
+            arg = arg.__name__
+        return arg
+
+    def __call__(self, *args):
+        fullname = ''.join(
+            [self._name, '<', ','.join(map(self._arg_to_str, args))])
+        if fullname[-1] == '>':
+            fullname += ' >'
+        else:
+            fullname += '>'
+        return getattr(self._scope, fullname)
+
+
+def clgen_callback(name):
+    return get_pycppclass(name)
+cppyy._set_class_generator(clgen_callback)
+
+def make_static_function(func_name, cppol):
+    def function(*args):
+        return cppol.call(None, *args)
+    function.__name__ = func_name
+    function.__doc__ = cppol.signature()
+    return staticmethod(function)
+
+def make_method(meth_name, cppol):
+    def method(self, *args):
+        return cppol.call(self, *args)
+    method.__name__ = meth_name
+    method.__doc__ = cppol.signature()
+    return method
+
+
+def make_datamember(cppdm):
+    rettype = cppdm.get_returntype()
+    if not rettype:                              # return builtin type
+        cppclass = None
+    else:                                        # return instance
+        try:
+            cppclass = get_pycppclass(rettype)
+        except AttributeError:
+            import warnings
+            warnings.warn("class %s unknown: no data member access" % rettype,
+                          RuntimeWarning)
+            cppclass = None
+    if cppdm.is_static():
+        def binder(obj):
+            return cppdm.get(None, cppclass)
+        def setter(obj, value):
+            return cppdm.set(None, value)
+    else:
+        def binder(obj):
+            return cppdm.get(obj, cppclass)
+        setter = cppdm.set
+    return property(binder, setter)
+
+
+def make_cppnamespace(scope, namespace_name, cppns, build_in_full=True):
+    # build up a representation of a C++ namespace (namespaces are classes)
+
+    # create a meta class to allow properties (for static data write access)
+    metans = type(CppyyNamespaceMeta)(namespace_name+'_meta', (CppyyNamespaceMeta,), {})
+
+    if cppns:
+        d = {"_cpp_proxy" : cppns}
+    else:
+        d = dict()
+        def cpp_proxy_loader(cls):
+            cpp_proxy = cppyy._scope_byname(cls.__name__ != '::' and cls.__name__ or '')
+            del cls.__class__._cpp_proxy
+            cls._cpp_proxy = cpp_proxy
+            return cpp_proxy
+        metans._cpp_proxy = property(cpp_proxy_loader)
+
+    # create the python-side C++ namespace representation, cache in scope if given
+    pycppns = metans(namespace_name, (object,), d)
+    if scope:
+        setattr(scope, namespace_name, pycppns)
+
+    if build_in_full:   # if False, rely on lazy build-up
+        # insert static methods into the "namespace" dictionary
+        for func_name in cppns.get_method_names():
+            cppol = cppns.get_overload(func_name)
+            pyfunc = make_static_function(func_name, cppol)
+            setattr(pycppns, func_name, pyfunc)
+
+        # add all data members to the dictionary of the class to be created, and
+        # static ones also to the meta class (needed for property setters)
+        for dm in cppns.get_datamember_names():
+            cppdm = cppns.get_datamember(dm)
+            pydm = make_datamember(cppdm)
+            setattr(pycppns, dm, pydm)
+            setattr(metans, dm, pydm)
+
+    return pycppns
+
+def _drop_cycles(bases):
+    # TODO: figure this out, as it seems to be a PyPy bug?!
+    for b1 in bases:
+        for b2 in bases:
+            if not (b1 is b2) and issubclass(b2, b1):
+                bases.remove(b1)   # removes lateral class
+                break
+    return tuple(bases)
+
+def make_new(class_name, cppclass):
+    try:
+        constructor_overload = cppclass.get_overload(cppclass.type_name)
+    except AttributeError:
+        msg = "cannot instantiate abstract class '%s'" % class_name
+        def __new__(cls, *args):
+            raise TypeError(msg)
+    else:
+        def __new__(cls, *args):
+            return constructor_overload.call(None, *args)
+    return __new__
+
+def make_pycppclass(scope, class_name, final_class_name, cppclass):
+
+    # get a list of base classes for class creation
+    bases = [get_pycppclass(base) for base in cppclass.get_base_names()]
+    if not bases:
+        bases = [CPPObject,]
+    else:
+        # it's technically possible that the required class now has been built
+        # if one of the base classes uses it in e.g. a function interface
+        try:
+            return scope.__dict__[final_class_name]
+        except KeyError:
+            pass
+
+    # create a meta class to allow properties (for static data write access)
+    metabases = [type(base) for base in bases]
+    metacpp = type(CppyyClass)(class_name+'_meta', _drop_cycles(metabases), {})
+
+    # create the python-side C++ class representation
+    def dispatch(self, name, signature):
+        cppol = cppclass.dispatch(name, signature)
+        return types.MethodType(make_method(name, cppol), self, type(self))
+    d = {"_cpp_proxy"   : cppclass,
+         "__dispatch__" : dispatch,
+         "__new__"      : make_new(class_name, cppclass),
+         }
+    pycppclass = metacpp(class_name, _drop_cycles(bases), d)
+ 
+    # cache result early so that the class methods can find the class itself
+    setattr(scope, final_class_name, pycppclass)
+
+    # insert (static) methods into the class dictionary
+    for meth_name in cppclass.get_method_names():
+        cppol = cppclass.get_overload(meth_name)
+        if cppol.is_static():
+            setattr(pycppclass, meth_name, make_static_function(meth_name, cppol))
+        else:
+            setattr(pycppclass, meth_name, make_method(meth_name, cppol))
+
+    # add all data members to the dictionary of the class to be created, and
+    # static ones also to the meta class (needed for property setters)
+    for dm_name in cppclass.get_datamember_names():
+        cppdm = cppclass.get_datamember(dm_name)
+        pydm = make_datamember(cppdm)
+
+        setattr(pycppclass, dm_name, pydm)
+        if cppdm.is_static():
+            setattr(metacpp, dm_name, pydm)
+
+    _pythonize(pycppclass)
+    cppyy._register_class(pycppclass)
+    return pycppclass
+
+def make_cpptemplatetype(scope, template_name):
+    return CppyyTemplateType(scope, template_name)
+
+
+def get_pycppitem(scope, name):
+    # resolve typedefs/aliases
+    full_name = (scope == gbl) and name or (scope.__name__+'::'+name)
+    true_name = cppyy._resolve_name(full_name)
+    if true_name != full_name:
+        return get_pycppclass(true_name)
+
+    pycppitem = None
+
+    # classes
+    cppitem = cppyy._scope_byname(true_name)
+    if cppitem:
+        if cppitem.is_namespace():
+            pycppitem = make_cppnamespace(scope, true_name, cppitem)
+            setattr(scope, name, pycppitem)
+        else:
+            pycppitem = make_pycppclass(scope, true_name, name, cppitem)
+
+    # templates
+    if not cppitem:
+        cppitem = cppyy._template_byname(true_name)
+        if cppitem:
+            pycppitem = make_cpptemplatetype(scope, name)
+            setattr(scope, name, pycppitem)
+
+    # functions
+    if not cppitem:
+        try:
+            cppitem = scope._cpp_proxy.get_overload(name)
+            pycppitem = make_static_function(name, cppitem)
+            setattr(scope.__class__, name, pycppitem)
+            pycppitem = getattr(scope, name)      # binds function as needed
+        except AttributeError:
+            pass
+
+    # data
+    if not cppitem:
+        try:
+            cppitem = scope._cpp_proxy.get_datamember(name)
+            pycppitem = make_datamember(cppitem)
+            setattr(scope, name, pycppitem)
+            if cppitem.is_static():
+                setattr(scope.__class__, name, pycppitem)
+            pycppitem = getattr(scope, name)      # gets actual property value
+        except AttributeError:
+            pass
+
+    if not (pycppitem is None):   # pycppitem could be a bound C++ NULL, so check explicitly for Py_None
+        return pycppitem
+
+    raise AttributeError("'%s' has no attribute '%s'" % (str(scope), name))
+
+
+def scope_splitter(name):
+    is_open_template, scope = 0, ""
+    for c in name:
+        if c == ':' and not is_open_template:
+            if scope:
+                yield scope
+                scope = ""
+            continue
+        elif c == '<':
+            is_open_template += 1
+        elif c == '>':
+            is_open_template -= 1
+        scope += c
+    yield scope
+
+def get_pycppclass(name):
+    # break up the name, to walk the scopes and get the class recursively
+    scope = gbl
+    for part in scope_splitter(name):
+        scope = getattr(scope, part)
+    return scope
+
+
+# pythonization by decoration (move to their own file?)
+def python_style_getitem(self, idx):
+    # python-style indexing: check for size and allow indexing from the back
+    sz = len(self)
+    if idx < 0: idx = sz + idx
+    if idx < sz:
+        return self._getitem__unchecked(idx)
+    raise IndexError('index out of range: %d requested for %s of size %d' % (idx, str(self), sz))
+
+def python_style_sliceable_getitem(self, slice_or_idx):
+    if type(slice_or_idx) == types.SliceType:
+        nseq = self.__class__()
+        nseq += [python_style_getitem(self, i) \
+                    for i in range(*slice_or_idx.indices(len(self)))]
+        return nseq
+    else:
+        return python_style_getitem(self, slice_or_idx)
+
+_pythonizations = {}
+def _pythonize(pyclass):
+
+    try:
+        _pythonizations[pyclass.__name__](pyclass)
+    except KeyError:
+        pass
+
+    # map size -> __len__ (generally true for STL)
+    if hasattr(pyclass, 'size') and \
+            not hasattr(pyclass, '__len__') and callable(pyclass.size):
+        pyclass.__len__ = pyclass.size
+
+    # map push_back -> __iadd__ (generally true for STL)
+    if hasattr(pyclass, 'push_back') and not hasattr(pyclass, '__iadd__'):
+        def __iadd__(self, ll):
+            [self.push_back(x) for x in ll]
+            return self
+        pyclass.__iadd__ = __iadd__
+
+    # for STL iterators, whose comparison functions live globally for gcc
+    # TODO: this needs to be solved fundamentally for all classes
+    if 'iterator' in pyclass.__name__:
+        if hasattr(gbl, '__gnu_cxx'):
+            if hasattr(gbl.__gnu_cxx, '__eq__'):
+                setattr(pyclass, '__eq__', gbl.__gnu_cxx.__eq__)
+            if hasattr(gbl.__gnu_cxx, '__ne__'):
+                setattr(pyclass, '__ne__', gbl.__gnu_cxx.__ne__)
+
+    # map begin()/end() protocol to iter protocol
+    if hasattr(pyclass, 'begin') and hasattr(pyclass, 'end'):
+        # TODO: make gnu-independent
+        def __iter__(self):
+            iter = self.begin()
+            while gbl.__gnu_cxx.__ne__(iter, self.end()):
+                yield iter.__deref__()
+                iter.__preinc__()
+            iter.destruct()
+            raise StopIteration
+        pyclass.__iter__ = __iter__
+
+    # combine __getitem__ and __len__ to make a pythonized __getitem__
+    if hasattr(pyclass, '__getitem__') and hasattr(pyclass, '__len__'):
+        pyclass._getitem__unchecked = pyclass.__getitem__
+        if hasattr(pyclass, '__setitem__') and hasattr(pyclass, '__iadd__'):
+            pyclass.__getitem__ = python_style_sliceable_getitem
+        else:
+            pyclass.__getitem__ = python_style_getitem
+
+    # string comparisons (note: CINT backend requires the simple name 'string')
+    if pyclass.__name__ == 'std::basic_string<char>' or pyclass.__name__ == 'string':
+        def eq(self, other):
+            if type(other) == pyclass:
+                return self.c_str() == other.c_str()
+            else:
+                return self.c_str() == other
+        pyclass.__eq__ = eq
+        pyclass.__str__ = pyclass.c_str
+
+    # TODO: clean this up
+    # fixup lack of __getitem__ if no const return
+    if hasattr(pyclass, '__setitem__') and not hasattr(pyclass, '__getitem__'):
+        pyclass.__getitem__ = pyclass.__setitem__
+
+_loaded_dictionaries = {}
+def load_reflection_info(name):
+    try:
+        return _loaded_dictionaries[name]
+    except KeyError:
+        dct = cppyy._load_dictionary(name)
+        _loaded_dictionaries[name] = dct
+        return dct
+    
+
+# user interface objects (note the two-step of not calling scope_byname here:
+# creation of global functions may cause the creation of classes in the global
+# namespace, so gbl must exist at that point to cache them)
+gbl = make_cppnamespace(None, "::", None, False)   # global C++ namespace
+
+# mostly for the benefit of the CINT backend, which treats std as special
+gbl.std = make_cppnamespace(None, "std", None, False)
+
+# user-defined pythonizations interface
+_pythonizations = {}
+def add_pythonization(class_name, callback):
+    if not callable(callback):
+        raise TypeError("given '%s' object is not callable" % str(callback))
+    _pythonizations[class_name] = callback
diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/src/cintcwrapper.cxx
@@ -0,0 +1,791 @@
+#include "cppyy.h"
+#include "cintcwrapper.h"
+
+#include "Api.h"
+
+#include "TROOT.h"
+#include "TError.h"
+#include "TList.h"
+#include "TSystem.h"
+
+#include "TApplication.h"
+#include "TInterpreter.h"
+#include "Getline.h"
+
+#include "TBaseClass.h"
+#include "TClass.h"
+#include "TClassEdit.h"
+#include "TClassRef.h"
+#include "TDataMember.h"
+#include "TFunction.h"
+#include "TGlobal.h"
+#include "TMethod.h"
+#include "TMethodArg.h"
+
+#include <assert.h>
+#include <string.h>
+#include <map>
+#include <sstream>
+#include <string>
+#include <utility>
+
+
+/*  CINT internals (some won't work on Windows) -------------------------- */
+extern long G__store_struct_offset;
+extern "C" void* G__SetShlHandle(char*);
+extern "C" void G__LockCriticalSection();
+extern "C" void G__UnlockCriticalSection();
+
+#define G__SETMEMFUNCENV      (long)0x7fff0035
+#define G__NOP                (long)0x7fff00ff
+
+namespace {
+
+class Cppyy_OpenedTClass : public TDictionary {
+public:
+    mutable TObjArray* fStreamerInfo;    //Array of TVirtualStreamerInfo
+    mutable std::map<std::string, TObjArray*>* fConversionStreamerInfo; //Array of the streamer infos derived from another class.
+    TList*             fRealData;       //linked list for persistent members including base classes
+    TList*             fBase;           //linked list for base classes
+    TList*             fData;           //linked list for data members
+    TList*             fMethod;         //linked list for methods
+    TList*             fAllPubData;     //all public data members (including from base classes)
+    TList*             fAllPubMethod;   //all public methods (including from base classes)
+};
+
+} // unnamed namespace
+
+
+/* data for life time management ------------------------------------------ */
+#define GLOBAL_HANDLE 1l
+
+typedef std::vector<TClassRef> ClassRefs_t;
+static ClassRefs_t g_classrefs(1);
+
+typedef std::map<std::string, ClassRefs_t::size_type> ClassRefIndices_t;
+static ClassRefIndices_t g_classref_indices;
+
+class ClassRefsInit {
+public:
+    ClassRefsInit() {   // setup dummy holders for global and std namespaces
+        assert(g_classrefs.size() == (ClassRefs_t::size_type)GLOBAL_HANDLE);
+        g_classref_indices[""] = (ClassRefs_t::size_type)GLOBAL_HANDLE;
+        g_classrefs.push_back(TClassRef(""));
+        g_classref_indices["std"] = g_classrefs.size();
+        g_classrefs.push_back(TClassRef(""));    // CINT ignores std
+        g_classref_indices["::std"] = g_classrefs.size();
+        g_classrefs.push_back(TClassRef(""));    // id.
+    }
+};
+static ClassRefsInit _classrefs_init;
+
+typedef std::vector<TFunction> GlobalFuncs_t;
+static GlobalFuncs_t g_globalfuncs;
+
+typedef std::vector<TGlobal> GlobalVars_t;
+static GlobalVars_t g_globalvars;
+
+
+/* initialization of the ROOT system (debatable ... ) --------------------- */
+namespace {
+
+class TCppyyApplication : public TApplication {
+public:
+    TCppyyApplication(const char* acn, Int_t* argc, char** argv, Bool_t do_load = kTRUE)
+           : TApplication(acn, argc, argv) {
+
+       // Explicitly load libMathCore as CINT will not auto load it when using one
+       // of its globals. Once moved to Cling, which should work correctly, we
+       // can remove this statement.
+       gSystem->Load("libMathCore");
+
+       if (do_load) {
+            // follow TRint to minimize differences with CINT
+            ProcessLine("#include <iostream>", kTRUE);
+            ProcessLine("#include <_string>",  kTRUE); // for std::string iostream.
+            ProcessLine("#include <DllImport.h>", kTRUE);// Defined R__EXTERN
+            ProcessLine("#include <vector>",   kTRUE); // needed because they're used within the
+            ProcessLine("#include <pair>",     kTRUE); //  core ROOT dicts and CINT won't be able
+                                                       //  to properly unload these files
+        }
+
+        // save current interpreter context
+        gInterpreter->SaveContext();
+        gInterpreter->SaveGlobalsContext();
+
+        // prevent crashes on accessing history
+        Gl_histinit((char*)"-");
+
+        // prevent ROOT from exiting python
+        SetReturnFromRun(kTRUE);
+
+        // enable auto-loader
+        gInterpreter->EnableAutoLoading();
+    }
+};
+
+static const char* appname = "pypy-cppyy";
+
+class ApplicationStarter {
+public:
+    ApplicationStarter() {
+        if (!gApplication) {
+            int argc = 1;
+            char* argv[1]; argv[0] = (char*)appname;
+            gApplication = new TCppyyApplication(appname, &argc, argv, kTRUE);
+        }
+    }
+} _applicationStarter;
+
+} // unnamed namespace
+
+
+/* local helpers ---------------------------------------------------------- */
+static inline char* cppstring_to_cstring(const std::string& name) {
+    char* name_char = (char*)malloc(name.size() + 1);
+    strcpy(name_char, name.c_str());
+    return name_char;
+}
+
+static inline char* type_cppstring_to_cstring(const std::string& tname) {
+    G__TypeInfo ti(tname.c_str());
+    std::string true_name = ti.IsValid() ? ti.TrueName() : tname;
+    return cppstring_to_cstring(true_name);
+}
+
+static inline TClassRef type_from_handle(cppyy_type_t handle) {
+    return g_classrefs[(ClassRefs_t::size_type)handle];
+}
+
+static inline TFunction* type_get_method(cppyy_type_t handle, int method_index) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass())
+        return (TFunction*)cr->GetListOfMethods()->At(method_index);
+    return &g_globalfuncs[method_index];
+}
+
+
+static inline void fixup_args(G__param* libp) {
+    for (int i = 0; i < libp->paran; ++i) {
+        libp->para[i].ref = libp->para[i].obj.i;
+        const char partype = libp->para[i].type;
+        switch (partype) {
+        case 'p': {
+            libp->para[i].obj.i = (long)&libp->para[i].ref;
+            break;
+        }
+        case 'r': {
+            libp->para[i].ref = (long)&libp->para[i].obj.i;
+            break;
+        }
+        case 'f': {
+            assert(sizeof(float) <= sizeof(long));
+            long val = libp->para[i].obj.i;
+            void* pval = (void*)&val;
+            libp->para[i].obj.d = *(float*)pval;
+            break;
+        }
+        case 'F': {
+            libp->para[i].ref = (long)&libp->para[i].obj.i;
+            libp->para[i].type = 'f';
+            break;
+        }
+        case 'D': {
+            libp->para[i].ref = (long)&libp->para[i].obj.i;
+            libp->para[i].type = 'd';
+            break;
+
+        }
+        }
+    }
+}
+
+
+/* name to opaque C++ scope representation -------------------------------- */
+char* cppyy_resolve_name(const char* cppitem_name) {
+    if (strcmp(cppitem_name, "") == 0)
+        return cppstring_to_cstring(cppitem_name);
+    G__TypeInfo ti(cppitem_name);
+    if (ti.IsValid()) {
+        if (ti.Property() & G__BIT_ISENUM)
+            return cppstring_to_cstring("unsigned int");
+        return cppstring_to_cstring(ti.TrueName());
+    }
+    return cppstring_to_cstring(cppitem_name);
+}
+
+cppyy_scope_t cppyy_get_scope(const char* scope_name) {
+    ClassRefIndices_t::iterator icr = g_classref_indices.find(scope_name);
+    if (icr != g_classref_indices.end())
+        return (cppyy_type_t)icr->second;
+
+    // use TClass directly, to enable auto-loading
+    TClassRef cr(TClass::GetClass(scope_name, kTRUE, kTRUE));
+    if (!cr.GetClass())
+        return (cppyy_type_t)NULL;
+
+    if (!cr->GetClassInfo())
+        return (cppyy_type_t)NULL;
+
+    if (!G__TypeInfo(scope_name).IsValid())
+        return (cppyy_type_t)NULL;
+
+    ClassRefs_t::size_type sz = g_classrefs.size();
+    g_classref_indices[scope_name] = sz;
+    g_classrefs.push_back(TClassRef(scope_name));
+    return (cppyy_scope_t)sz;
+}
+
+cppyy_type_t cppyy_get_template(const char* template_name) {
+    ClassRefIndices_t::iterator icr = g_classref_indices.find(template_name);
+    if (icr != g_classref_indices.end())
+        return (cppyy_type_t)icr->second;
+
+    if (!G__defined_templateclass((char*)template_name))
+        return (cppyy_type_t)NULL;
+
+    // the following yields a dummy TClassRef, but its name can be queried
+    ClassRefs_t::size_type sz = g_classrefs.size();
+    g_classref_indices[template_name] = sz;
+    g_classrefs.push_back(TClassRef(template_name));
+    return (cppyy_type_t)sz;
+}
+
+cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj) {
+    TClassRef cr = type_from_handle(klass);


More information about the pypy-commit mailing list