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

bivab noreply at buildbot.pypy.org
Mon Aug 6 14:57:14 CEST 2012


Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r56597:2e5581814557
Date: 2012-08-06 14:56 +0200
http://bitbucket.org/pypy/pypy/changeset/2e5581814557/

Log:	merge heads

diff too long, truncating to 10000 out of 13587 lines

diff --git a/lib_pypy/PyQt4.py b/lib_pypy/PyQt4.py
deleted file mode 100755
--- 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/_rpyc_support.py b/lib_pypy/_rpyc_support.py
deleted file mode 100755
--- 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/distributed/__init__.py b/lib_pypy/distributed/__init__.py
deleted file mode 100755
--- 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 100755
--- 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 100755
--- 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 100755
--- 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 100755
--- 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 100755
--- 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 100755
--- 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 100755
diff --git a/lib_pypy/distributed/test/test_distributed.py b/lib_pypy/distributed/test/test_distributed.py
deleted file mode 100755
--- 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 100755
--- 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 100755
--- 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 100755
--- 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/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)):
     
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/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
@@ -3389,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):
@@ -3793,7 +3809,37 @@
         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/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",
diff --git a/pypy/config/test/test_pypyoption.py b/pypy/config/test/test_pypyoption.py
--- a/pypy/config/test/test_pypyoption.py
+++ b/pypy/config/test/test_pypyoption.py
@@ -71,7 +71,7 @@
         c = Config(descr)
         for path in c.getpaths(include_groups=True):
             fn = prefix + "." + path + ".txt"
-            yield check_file_exists, fn
+            yield fn, check_file_exists, fn
 
 def test__ffi_opt():
     config = get_pypy_config(translating=True)
diff --git a/pypy/doc/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
@@ -153,6 +153,7 @@
 
 Automatic class loader
 ======================
+
 There is one big problem in the code above, that prevents its use in a (large
 scale) production setting: the explicit loading of the reflection library.
 Clearly, if explicit load statements such as these show up in code downstream
@@ -164,7 +165,9 @@
 The class loader makes use of so-called rootmap files, which ``genreflex``
 can produce.
 These files contain the list of available C++ classes and specify the library
-that needs to be loaded for their use.
+that needs to be loaded for their use (as an aside, this listing allows for a
+cross-check to see whether reflection info is generated for all classes that
+you expect).
 By convention, the rootmap files should be located next to the reflection info
 libraries, so that they can be found through the normal shared library search
 path.
@@ -198,6 +201,7 @@
 
 Advanced example
 ================
+
 The following snippet of C++ is very contrived, to allow showing that such
 pathological code can be handled and to show how certain features play out in
 practice::
@@ -253,6 +257,9 @@
 With the aid of a selection file, a large project can be easily managed:
 simply ``#include`` all relevant headers into a single header file that is
 handed to ``genreflex``.
+In fact, if you hand multiple header files to ``genreflex``, then a selection
+file is almost obligatory: without it, only classes from the last header will
+be selected.
 Then, apply a selection file to pick up all the relevant classes.
 For our purposes, the following rather straightforward selection will do
 (the name ``lcgdict`` for the root is historical, but required)::
@@ -325,15 +332,43 @@
 (active memory management is one such case), but by and large, if the use of a
 feature does not strike you as obvious, it is more likely to simply be a bug.
 That is a strong statement to make, but also a worthy goal.
+For the C++ side of the examples, refer to this `example code`_, which was
+bound using::
+
+    $ genreflex example.h --deep --rootmap=libexampleDict.rootmap --rootmap-lib=libexampleDict.so
+    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include example_rflx.cpp -o libexampleDict.so -L$ROOTSYS/lib -lReflex
+
+.. _`example code`: cppyy_example.html
 
 * **abstract classes**: Are represented as python classes, since they are
   needed to complete the inheritance hierarchies, but will raise an exception
   if an attempt is made to instantiate from them.
+  Example::
+
+    >>>> from cppyy.gbl import AbstractClass, ConcreteClass
+    >>>> a = AbstractClass()
+    Traceback (most recent call last):
+      File "<console>", line 1, in <module>
+    TypeError: cannot instantiate abstract class 'AbstractClass'
+    >>>> issubclass(ConcreteClass, AbstractClass)
+    True
+    >>>> c = ConcreteClass()
+    >>>> isinstance(c, AbstractClass)
+    True
+    >>>>
 
 * **arrays**: Supported for builtin data types only, as used from module
   ``array``.
   Out-of-bounds checking is limited to those cases where the size is known at
   compile time (and hence part of the reflection info).
+  Example::
+
+    >>>> from cppyy.gbl import ConcreteClass
+    >>>> from array import array
+    >>>> c = ConcreteClass()
+    >>>> c.array_method(array('d', [1., 2., 3., 4.]), 4)
+    1 2 3 4
+    >>>> 
 
 * **builtin data types**: Map onto the expected equivalent python types, with
   the caveat that there may be size differences, and thus it is possible that
@@ -344,23 +379,77 @@
   in the hierarchy of the object being returned.
   This is important to preserve object identity as well as to make casting,
   a pure C++ feature after all, superfluous.
+  Example::
+
+    >>>> from cppyy.gbl import AbstractClass, ConcreteClass
+    >>>> c = ConcreteClass()
+    >>>> ConcreteClass.show_autocast.__doc__
+    'AbstractClass* ConcreteClass::show_autocast()'
+    >>>> d = c.show_autocast()
+    >>>> type(d)
+    <class '__main__.ConcreteClass'>
+    >>>>
+
+  However, if need be, you can perform C++-style reinterpret_casts (i.e.
+  without taking offsets into account), by taking and rebinding the address
+  of an object::
+
+    >>>> from cppyy import addressof, bind_object
+    >>>> e = bind_object(addressof(d), AbstractClass)
+    >>>> type(e)
+    <class '__main__.AbstractClass'>
+    >>>>
 
 * **classes and structs**: Get mapped onto python classes, where they can be
   instantiated as expected.
   If classes are inner classes or live in a namespace, their naming and
   location will reflect that.
+  Example::
+
+    >>>> from cppyy.gbl import ConcreteClass, Namespace
+    >>>> ConcreteClass == Namespace.ConcreteClass
+    False
+    >>>> n = Namespace.ConcreteClass.NestedClass()
+    >>>> type(n)
+    <class '__main__.Namespace::ConcreteClass::NestedClass'>
+    >>>> 
 
 * **data members**: Public data members are represented as python properties
   and provide read and write access on instances as expected.
+  Private and protected data members are not accessible.
+  Example::
+
+    >>>> from cppyy.gbl import ConcreteClass
+    >>>> c = ConcreteClass()
+    >>>> c.m_int
+    42
+    >>>>
 
 * **default arguments**: C++ default arguments work as expected, but python
   keywords are not supported.
   It is technically possible to support keywords, but for the C++ interface,
   the formal argument names have no meaning and are not considered part of the
   API, hence it is not a good idea to use keywords.
+  Example::
+
+    >>>> from cppyy.gbl import ConcreteClass
+    >>>> c = ConcreteClass()       # uses default argument
+    >>>> c.m_int
+    42
+    >>>> c = ConcreteClass(13)
+    >>>> c.m_int
+    13
+    >>>>
 
 * **doc strings**: The doc string of a method or function contains the C++
   arguments and return types of all overloads of that name, as applicable.
+  Example::
+
+    >>>> from cppyy.gbl import ConcreteClass
+    >>>> print ConcreteClass.array_method.__doc__
+    void ConcreteClass::array_method(int*, int)
+    void ConcreteClass::array_method(double*, int)
+    >>>> 
 
 * **enums**: Are translated as ints with no further checking.
 
@@ -375,11 +464,40 @@
   This is a current, not a fundamental, limitation.
   The C++ side will not see any overridden methods on the python side, as
   cross-inheritance is planned but not yet supported.
+  Example::
+
+    >>>> from cppyy.gbl import ConcreteClass
+    >>>> help(ConcreteClass)
+    Help on class ConcreteClass in module __main__:
+
+    class ConcreteClass(AbstractClass)
+     |  Method resolution order:
+     |      ConcreteClass
+     |      AbstractClass
+     |      cppyy.CPPObject
+     |      __builtin__.CPPInstance
+     |      __builtin__.object
+     |  
+     |  Methods defined here:
+     |  
+     |  ConcreteClass(self, *args)
+     |      ConcreteClass::ConcreteClass(const ConcreteClass&)
+     |      ConcreteClass::ConcreteClass(int)
+     |      ConcreteClass::ConcreteClass()
+     |
+     etc. ....
 
 * **memory**: C++ instances created by calling their constructor from python
   are owned by python.
   You can check/change the ownership with the _python_owns flag that every
   bound instance carries.
+  Example::
+
+    >>>> from cppyy.gbl import ConcreteClass
+    >>>> c = ConcreteClass()
+    >>>> c._python_owns            # True: object created in Python
+    True
+    >>>> 
 
 * **methods**: Are represented as python methods and work as expected.
   They are first class objects and can be bound to an instance.
@@ -395,23 +513,34 @@
   Namespaces are more open-ended than classes, so sometimes initial access may
   result in updates as data and functions are looked up and constructed
   lazily.
-  Thus the result of ``dir()`` on a namespace should not be relied upon: it
-  only shows the already accessed members. (TODO: to be fixed by implementing
-  __dir__.)
+  Thus the result of ``dir()`` on a namespace shows the classes available,
+  even if they may not have been created yet.
+  It does not show classes that could potentially be loaded by the class
+  loader.
+  Once created, namespaces are registered as modules, to allow importing from
+  them.
+  Namespace currently do not work with the class loader.
+  Fixing these bootstrap problems is on the TODO list.
   The global namespace is ``cppyy.gbl``.
 
 * **operator conversions**: If defined in the C++ class and a python
   equivalent exists (i.e. all builtin integer and floating point types, as well
   as ``bool``), it will map onto that python conversion.
   Note that ``char*`` is mapped onto ``__str__``.
+  Example::
+
+    >>>> from cppyy.gbl import ConcreteClass
+    >>>> print ConcreteClass()
+    Hello operator const char*!
+    >>>> 
 
 * **operator overloads**: If defined in the C++ class and if a python
   equivalent is available (not always the case, think e.g. of ``operator||``),
   then they work as expected.
   Special care needs to be taken for global operator overloads in C++: first,
   make sure that they are actually reflected, especially for the global
-  overloads for ``operator==`` and ``operator!=`` of STL iterators in the case
-  of gcc.
+  overloads for ``operator==`` and ``operator!=`` of STL vector iterators in
+  the case of gcc (note that they are not needed to iterator over a vector).
   Second, make sure that reflection info is loaded in the proper order.
   I.e. that these global overloads are available before use.
 
@@ -441,17 +570,30 @@
   will be returned if the return type is ``const char*``.
 
 * **templated classes**: Are represented in a meta-class style in python.
-  This looks a little bit confusing, but conceptually is rather natural.
+  This may look a little bit confusing, but conceptually is rather natural.
   For example, given the class ``std::vector<int>``, the meta-class part would
-  be ``std.vector`` in python.
+  be ``std.vector``.
   Then, to get the instantiation on ``int``, do ``std.vector(int)`` and to
-  create an instance of that class, do ``std.vector(int)()``.
+  create an instance of that class, do ``std.vector(int)()``::
+
+    >>>> import cppyy
+    >>>> cppyy.load_reflection_info('libexampleDict.so')
+    >>>> cppyy.gbl.std.vector                # template metatype
+    <cppyy.CppyyTemplateType object at 0x00007fcdd330f1a0>
+    >>>> cppyy.gbl.std.vector(int)           # instantiates template -> class
+    <class '__main__.std::vector<int>'>
+    >>>> cppyy.gbl.std.vector(int)()         # instantiates class -> object
+    <__main__.std::vector<int> object at 0x00007fe480ba4bc0>
+    >>>> 
+
   Note that templates can be build up by handing actual types to the class
   instantiation (as done in this vector example), or by passing in the list of
   template arguments as a string.
   The former is a lot easier to work with if you have template instantiations
-  using classes that themselves are templates (etc.) in the arguments.
-  All classes must already exist in the loaded reflection info.
+  using classes that themselves are templates in  the arguments (think e.g a
+  vector of vectors).
+  All template classes must already exist in the loaded reflection info, they
+  do not work (yet) with the class loader.
 
 * **typedefs**: Are simple python references to the actual classes to which
   they refer.
@@ -502,11 +644,19 @@
 
 If you know for certain that all symbols will be linked in from other sources,
 you can also declare the explicit template instantiation ``extern``.
+An alternative is to add an object to an unnamed namespace::
 
-Unfortunately, this is not enough for gcc.
-The iterators, if they are going to be used, need to be instantiated as well,
-as do the comparison operators on those iterators, as these live in an
-internal namespace, rather than in the iterator classes.
+    namespace {
+        std::vector<MyClass> vmc;
+    } // unnamed namespace
+
+Unfortunately, this is not always enough for gcc.
+The iterators of vectors, if they are going to be used, need to be
+instantiated as well, as do the comparison operators on those iterators, as
+these live in an internal namespace, rather than in the iterator classes.
+Note that you do NOT need this iterators to iterator over a vector.
+You only need them if you plan to explicitly call e.g. ``begin`` and ``end``
+methods, and do comparisons of iterators.
 One way to handle this, is to deal with this once in a macro, then reuse that
 macro for all ``vector`` classes.
 Thus, the header above needs this (again protected with
@@ -533,8 +683,6 @@
     <lcgdict>
         <class pattern="std::vector<*>" />
         <class pattern="std::vector<*>::iterator" />
-        <class pattern="std::_Vector_base<*>" />
-        <class pattern="std::_Vector_base<*>::_Vector_impl" />
         <function name="__gnu_cxx::operator=="/>
         <function name="__gnu_cxx::operator!="/>
 
@@ -549,7 +697,7 @@
 Note: this is a dirty corner that clearly could do with some automation,
 even if the macro already helps.
 Such automation is planned.
-In fact, in the cling world, the backend can perform the template
+In fact, in the Cling world, the backend can perform the template
 instantations and generate the reflection info on the fly, and none of the
 above will any longer be necessary.
 
@@ -568,7 +716,8 @@
     1 2 3
     >>>>
 
-Other templates work similarly.
+Other templates work similarly, but are typically simpler, as there are no
+similar issues with iterators for e.g. ``std::list``.
 The arguments to the template instantiation can either be a string with the
 full list of arguments, or the explicit classes.
 The latter makes for easier code writing if the classes passed to the
@@ -655,3 +804,15 @@
 In that wrapper script you can rename methods exactly the way you need it.
 
 In the cling world, all these differences will be resolved.
+
+
+Python3
+=======
+
+To change versions of CPython (to Python3, another version of Python, or later
+to the `Py3k`_ version of PyPy), the only part that requires recompilation is
+the bindings module, be it ``cppyy`` or ``libPyROOT.so`` (in PyCintex).
+Although ``genreflex`` is indeed a Python tool, the generated reflection
+information is completely independent of Python.
+
+.. _`Py3k`: https://bitbucket.org/pypy/pypy/src/py3k
diff --git a/pypy/doc/cppyy_example.rst b/pypy/doc/cppyy_example.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/cppyy_example.rst
@@ -0,0 +1,56 @@
+// File: example.h::
+
+    #include <iostream>
+    #include <vector>
+
+    class AbstractClass {
+    public:
+        virtual ~AbstractClass() {}
+        virtual void abstract_method() = 0;
+    };
+
+    class ConcreteClass : AbstractClass {
+    public:
+        ConcreteClass(int n=42) : m_int(n) {}
+        ~ConcreteClass() {}
+
+        virtual void abstract_method() {
+            std::cout << "called concrete method" << std::endl;
+        }
+
+        void array_method(int* ad, int size) {
+            for (int i=0; i < size; ++i)
+                std::cout << ad[i] << ' ';
+            std::cout << std::endl;
+        }
+
+        void array_method(double* ad, int size) {
+            for (int i=0; i < size; ++i)
+                std::cout << ad[i] << ' ';
+            std::cout << std::endl;
+        }
+
+        AbstractClass* show_autocast() {
+            return this;
+        }
+
+        operator const char*() {
+            return "Hello operator const char*!";
+        }
+
+    public:
+        int m_int;
+    };
+
+    namespace Namespace {
+
+       class ConcreteClass {
+       public:
+          class NestedClass {
+          public:
+             std::vector<int> m_v;
+          };
+
+       };
+
+    } // namespace Namespace
diff --git a/pypy/doc/image/agile-talk.jpg b/pypy/doc/image/agile-talk.jpg
deleted file mode 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
Binary file pypy/doc/image/sprint-tutorial.jpg has changed
diff --git a/pypy/doc/video-index.rst b/pypy/doc/video-index.rst
--- a/pypy/doc/video-index.rst
+++ b/pypy/doc/video-index.rst
@@ -2,39 +2,11 @@
 PyPy video documentation 
 =========================
 
-Requirements to download and view
----------------------------------
-
-In order to download the videos you need to point a
-BitTorrent client at the torrent files provided below. 
-We do not provide any other download method at this
-time.  Please get a BitTorrent client (such as bittorrent). 
-For a list of clients please 
-see http://en.wikipedia.org/wiki/Category:Free_BitTorrent_clients or 
-http://en.wikipedia.org/wiki/Comparison_of_BitTorrent_clients. 
-For more information about Bittorrent see 
-http://en.wikipedia.org/wiki/Bittorrent.
-
-In order to view the downloaded movies you need to 
-have a video player that supports DivX AVI files (DivX 5, mp3 audio)
-such as `mplayer`_, `xine`_, `vlc`_ or the windows media player.
-
-.. _`mplayer`: http://www.mplayerhq.hu/design7/dload.html
-.. _`xine`: http://www.xine-project.org
-.. _`vlc`: http://www.videolan.org/vlc/
-
-You can find the necessary codecs in the ffdshow-library:
-http://sourceforge.net/projects/ffdshow/
-
-or use the original divx codec (for Windows):
-http://www.divx.com/software/divx-plus
-
-
 Copyrights and Licensing 
 ----------------------------
 
-The following videos are copyrighted by merlinux gmbh and 
-published under the Creative Commons Attribution License 2.0 Germany: http://creativecommons.org/licenses/by/2.0/de/
+The following videos are copyrighted by merlinux gmbh and available on
+YouTube.
 
 If you need another license, don't hesitate to contact us. 
 
@@ -42,255 +14,202 @@
 Trailer: PyPy at the PyCon 2006
 -------------------------------
 
-130mb: http://buildbot.pypy.org/misc/torrent/pycon-trailer.avi.torrent
+This trailer shows the PyPy team at the PyCon 2006, a behind-the-scenes at
+sprints, talks and everywhere else.
 
-71mb: http://buildbot.pypy.org/misc/torrent/pycon-trailer-medium.avi.torrent
+.. raw:: html
 
-50mb: http://buildbot.pypy.org/misc/torrent/pycon-trailer-320x240.avi.torrent
-
-.. image:: image/pycon-trailer.jpg
-   :scale: 100
-   :alt: Trailer PyPy at PyCon
-   :align: left
-
-This trailer shows the PyPy team at the PyCon 2006, a behind-the-scenes at sprints, talks and everywhere else.
-
-PAL, 9 min, DivX AVI
-
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/WfGszrRUdtc?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Interview with Tim Peters
 -------------------------
 
-440mb: http://buildbot.pypy.org/misc/torrent/interview-timpeters-v2.avi.torrent
+Interview with CPython core developer Tim Peters at PyCon 2006, Dallas,
+US. (2006-03-02)
 
-138mb: http://buildbot.pypy.org/misc/torrent/interview-timpeters-320x240.avi.torrent
+Tim Peters, a longtime CPython core developer talks about how he got into
+Python, what he thinks about the PyPy project and why he thinks it would have
+never been possible in the US.
 
-.. image:: image/interview-timpeters.jpg
-   :scale: 100
-   :alt: Interview with Tim Peters
-   :align: left
+.. raw:: html
 
-Interview with CPython core developer Tim Peters at PyCon 2006, Dallas, US. (2006-03-02)
-
-PAL, 23 min, DivX AVI
-
-Tim Peters, a longtime CPython core developer talks about how he got into Python, what he thinks about the PyPy project and why he thinks it would have never been possible in the US.
-
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/1wAOy88WxmY?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Interview with Bob Ippolito
 ---------------------------
 
-155mb: http://buildbot.pypy.org/misc/torrent/interview-bobippolito-v2.avi.torrent
+What do you think about PyPy? Interview with American software developer Bob
+Ippolito at PyCon 2006, Dallas, US. (2006-03-01)
 
-50mb: http://buildbot.pypy.org/misc/torrent/interview-bobippolito-320x240.avi.torrent
+Bob Ippolito is an Open Source software developer from San Francisco and has
+been to two PyPy sprints. In this interview he is giving his opinion on the
+project.
 
-.. image:: image/interview-bobippolito.jpg
-   :scale: 100
-   :alt: Interview with Bob Ippolito
-   :align: left
+.. raw:: html
 
-What do you think about PyPy? Interview with American software developer Bob Ippolito at tPyCon 2006, Dallas, US. (2006-03-01)
-
-PAL 8 min, DivX AVI
-
-Bob Ippolito is an Open Source software developer from San Francisco and has been to two PyPy sprints. In this interview he is giving his opinion on the project.
-
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/c5rq4Q03zgg?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Introductory talk on PyPy
 -------------------------
 
-430mb: http://buildbot.pypy.org/misc/torrent/introductory-talk-pycon-v1.avi.torrent
-
-166mb: http://buildbot.pypy.org/misc/torrent/introductory-talk-pycon-320x240.avi.torrent
-
-.. image:: image/introductory-talk-pycon.jpg
-   :scale: 100
-   :alt: Introductory talk at PyCon 2006
-   :align: left
-
-This introductory talk is given by core developers Michael Hudson and Christian Tismer at PyCon 2006, Dallas, US. (2006-02-26)
-
-PAL, 28 min, divx AVI
+This introductory talk is given by core developers Michael Hudson and
+Christian Tismer at PyCon 2006, Dallas, US. (2006-02-26)
 
 Michael Hudson talks about the basic building blocks of Python, the currently
 available back-ends, and the status of PyPy in general. Christian Tismer takes
-over to explain how co-routines can be used to implement things like
-Stackless and Greenlets in PyPy.
+over to explain how co-routines can be used to implement things like Stackless
+and Greenlets in PyPy.
 
+.. raw:: html
+
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/AWUhXW2pLDE?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Talk on Agile Open Source Methods in the PyPy project
 -----------------------------------------------------
 
-395mb: http://buildbot.pypy.org/misc/torrent/agile-talk-v1.avi.torrent
-
-153mb: http://buildbot.pypy.org/misc/torrent/agile-talk-320x240.avi.torrent
-
-.. image:: image/agile-talk.jpg
-   :scale: 100
-   :alt: Agile talk
-   :align: left
-
-Core developer Holger Krekel and project manager Beatrice During are giving a talk on the agile open source methods used in the PyPy project at PyCon 2006, Dallas, US. (2006-02-26)
-
-PAL, 26 min, divx AVI
+Core developer Holger Krekel and project manager Beatrice During are giving a
+talk on the agile open source methods used in the PyPy project at PyCon 2006,
+Dallas, US. (2006-02-26)
 
 Holger Krekel explains more about the goals and history of PyPy, and the
 structure and organization behind it. Bea During describes the intricacies of
 driving a distributed community in an agile way, and how to combine that with
 the formalities required for EU funding.
 
+.. raw:: html
+
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/ed-zAxZtGlY?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 PyPy Architecture session
 -------------------------
 
-744mb: http://buildbot.pypy.org/misc/torrent/architecture-session-v1.avi.torrent
-
-288mb: http://buildbot.pypy.org/misc/torrent/architecture-session-320x240.avi.torrent
-
-.. image:: image/architecture-session.jpg
-   :scale: 100
-   :alt: Architecture session
-   :align: left
-
-This architecture session is given by core developers Holger Krekel and Armin Rigo at PyCon 2006, Dallas, US. (2006-02-26)
-
-PAL, 48 min, divx AVI
+This architecture session is given by core developers Holger Krekel and Armin
+Rigo at PyCon 2006, Dallas, US. (2006-02-26)
 
 Holger Krekel and Armin Rigo talk about the basic implementation,
-implementation level aspects and the RPython translation toolchain. This
-talk also gives an insight into how a developer works with these tools on
-a daily basis, and pays special attention to flow graphs.
+implementation level aspects and the RPython translation toolchain. This talk
+also gives an insight into how a developer works with these tools on a daily
+basis, and pays special attention to flow graphs.
 
+.. raw:: html
+
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/7opXGaQUUA4?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Sprint tutorial
 ---------------
 
-680mb: http://buildbot.pypy.org/misc/torrent/sprint-tutorial-v2.avi.torrent
+Sprint tutorial by core developer Michael Hudson at PyCon 2006, Dallas,
+US. (2006-02-27)
 
-263mb: http://buildbot.pypy.org/misc/torrent/sprint-tutorial-320x240.avi.torrent
+Michael Hudson gives an in-depth, very technical introduction to a PyPy
+sprint. The film provides a detailed and hands-on overview about the
+architecture of PyPy, especially the RPython translation toolchain.
 
-.. image:: image/sprint-tutorial.jpg
-   :scale: 100
-   :alt: Sprint Tutorial
-   :align: left
+.. raw:: html
 
-Sprint tutorial by core developer Michael Hudson at PyCon 2006, Dallas, US. (2006-02-27)
-
-PAL, 44 min, divx AVI
-
-Michael Hudson gives an in-depth, very technical introduction to a PyPy sprint. The film provides a detailed and hands-on overview about the architecture of PyPy, especially the RPython translation toolchain.
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/1YV7J74xrMI?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Scripting .NET with IronPython by Jim Hugunin
 ---------------------------------------------
 
-372mb: http://buildbot.pypy.org/misc/torrent/ironpython-talk-v2.avi.torrent
+Talk by Jim Hugunin (Microsoft) on the IronPython implementation on the .NET
+framework at the PyCon 2006, Dallas, US.
 
-270mb: http://buildbot.pypy.org/misc/torrent/ironpython-talk-320x240.avi.torrent
+Jim Hugunin talks about regression tests, the code generation and the object
+layout, the new-style instance and gives a CLS interop demo.
 
-.. image:: image/ironpython.jpg
-   :scale: 100
-   :alt: Jim Hugunin on IronPython
-   :align: left
+.. raw:: html
 
-Talk by Jim Hugunin (Microsoft) on the IronPython implementation on the .NET framework at this years PyCon, Dallas, US.
-
-PAL, 44 min, DivX AVI
-
-Jim Hugunin talks about regression tests, the code generation and the object layout, the new-style instance and gives a CLS interop demo.
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/bq9ZGN3-o80?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Bram Cohen, founder and developer of BitTorrent
 -----------------------------------------------
 
-509mb: http://buildbot.pypy.org/misc/torrent/bram-cohen-interview-v1.avi.torrent
+Bram Cohen is interviewed by Steve Holden at the PyCon 2006, Dallas, US.
 
-370mb: http://buildbot.pypy.org/misc/torrent/bram-cohen-interview-320x240.avi.torrent
+.. raw:: html
 
-.. image:: image/bram.jpg
-   :scale: 100
-   :alt: Bram Cohen on BitTorrent
-   :align: left
-
-Bram Cohen is interviewed by Steve Holden at this years PyCon, Dallas, US.
-
-PAL, 60 min, DivX AVI
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/EopmJWrLmWI?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Keynote speech by Guido van Rossum on the new Python 2.5 features
 -----------------------------------------------------------------
 
-695mb: http://buildbot.pypy.org/misc/torrent/keynote-speech_guido-van-rossum_v1.avi.torrent
+Guido van Rossum explains the new Python 2.5 features at the PyCon 2006,
+Dallas, US.
 
-430mb: http://buildbot.pypy.org/misc/torrent/keynote-speech_guido-van-rossum_320x240.avi.torrent
+.. raw:: html
 
-.. image:: image/guido.jpg
-   :scale: 100
-   :alt: Guido van Rossum on Python 2.5
-   :align: left
-
-Guido van Rossum explains the new Python 2.5 features at this years PyCon, Dallas, US.
-
-PAL, 70 min, DivX AVI
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/RR2sX8tFGsI?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Trailer: PyPy sprint at the University of Palma de Mallorca
 -----------------------------------------------------------
 
-166mb: http://buildbot.pypy.org/misc/torrent/mallorca-trailer-v1.avi.torrent
+This trailer shows the PyPy team at the sprint in Mallorca, a
+behind-the-scenes of a typical PyPy coding sprint and talk as well as
+everything else.
 
-88mb: http://buildbot.pypy.org/misc/torrent/mallorca-trailer-medium.avi.torrent
+.. raw:: html
 
-64mb: http://buildbot.pypy.org/misc/torrent/mallorca-trailer-320x240.avi.torrent
-
-.. image:: image/mallorca-trailer.jpg
-   :scale: 100
-   :alt: Trailer PyPy sprint in Mallorca
-   :align: left
-
-This trailer shows the PyPy team at the sprint in Mallorca, a behind-the-scenes of a typical PyPy coding sprint and talk as well as everything else.
-
-PAL, 11 min, DivX AVI
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/swsnRfj_cek?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 Coding discussion of core developers Armin Rigo and Samuele Pedroni
 -------------------------------------------------------------------
 
-620mb: http://buildbot.pypy.org/misc/torrent/coding-discussion-v1.avi.torrent
+Coding discussion between Armin Rigo and Samuele Pedroni during the PyPy
+sprint at the University of Palma de Mallorca, Spain. 27.1.2006
 
-240mb: http://buildbot.pypy.org/misc/torrent/coding-discussion-320x240.avi.torrent
+.. raw:: html
 
-.. image:: image/coding-discussion.jpg
-   :scale: 100
-   :alt: Coding discussion
-   :align: left
-
-Coding discussion between Armin Rigo and Samuele Pedroni during the PyPy sprint at the University of Palma de Mallorca, Spain. 27.1.2006
-
-PAL 40 min, DivX AVI
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/H_IgK9qmEss?rel=0"
+   frameborder="0" allowfullscreen></iframe>
 
 
 PyPy technical talk at the University of Palma de Mallorca
 ----------------------------------------------------------
 
-865mb: http://buildbot.pypy.org/misc/torrent/introductory-student-talk-v2.avi.torrent
-
-437mb: http://buildbot.pypy.org/misc/torrent/introductory-student-talk-320x240.avi.torrent
-
-.. image:: image/introductory-student-talk.jpg
-   :scale: 100
-   :alt: Introductory student talk
-   :align: left
-
 Technical talk on the PyPy project at the University of Palma de Mallorca, Spain. 27.1.2006
 
-PAL 72 min, DivX AVI
+Core developers Armin Rigo, Samuele Pedroni and Carl Friedrich Bolz are giving
+an overview of the PyPy architecture, the standard interpreter, the RPython
+translation toolchain and the just-in-time compiler.
 
-Core developers Armin Rigo, Samuele Pedroni and Carl Friedrich Bolz are giving an overview of the PyPy architecture, the standard interpreter, the RPython translation toolchain and the just-in-time compiler.
+.. raw:: html
 
+   <iframe width="420" height="315"
+   src="http://www.youtube.com/embed/6dnUzVQaSlg?rel=0"
+   frameborder="0" allowfullscreen></iframe>
+
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -14,5 +14,18 @@
 .. 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/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/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/interpreter/test/test_function.py b/pypy/interpreter/test/test_function.py
--- a/pypy/interpreter/test/test_function.py
+++ b/pypy/interpreter/test/test_function.py
@@ -16,6 +16,7 @@
         assert f.func_defaults == None
         assert f.func_dict == {}
         assert type(f.func_globals) == dict
+        assert f.func_globals is f.__globals__
         assert f.func_closure is None
         assert f.func_doc == None
         assert f.func_name == 'f'
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -37,7 +37,7 @@
         assert __total_ordering__ in (None, 'auto'), "Unknown value for __total_ordering"
         if __total_ordering__ == 'auto':
             self.auto_total_ordering()
-    
+
     def add_entries(self, **rawdict):
         # xxx fix the names of the methods to match what app-level expects
         for key, value in rawdict.items():
@@ -228,7 +228,7 @@
 
     def add(Proto):
         for key, value in Proto.__dict__.items():
-            if (not key.startswith('__') and not key.startswith('_mixin_') 
+            if (not key.startswith('__') and not key.startswith('_mixin_')
                     or key == '__del__'):
                 if hasattr(value, "func_name"):
                     value = func_with_new_name(value, value.func_name)
@@ -315,10 +315,10 @@
         class Proto(object):
             def getdict(self, space):
                 return self.w__dict__
-            
+
             def setdict(self, space, w_dict):
                 self.w__dict__ = check_new_dictionary(space, w_dict)
-            
+
             def user_setup(self, space, w_subtype):
                 self.w__dict__ = space.newdict(
                     instance=True)
@@ -383,7 +383,7 @@
             return %(name)s(%(args)s, %(extra)s)
         """
         miniglobals[cls_name] = cls
-    
+
     name = func.__name__
     extra = ', '.join(extraargs)
     from pypy.interpreter import pycode
@@ -503,7 +503,7 @@
                 space, '__delattr__',
                 self.reqcls, Arguments(space, [w_obj,
                                                space.wrap(self.name)]))
-    
+
     def descr_get_objclass(space, property):
         return property.objclass_getter(space)
 
@@ -521,7 +521,7 @@
             return space.w_None
         else:
             return w_value
-    
+
     return GetSetProperty(fget, cls=cls, doc=doc)
 
 GetSetProperty.typedef = TypeDef(
@@ -543,7 +543,7 @@
         self.index = index
         self.name = name
         self.w_cls = w_cls
-    
+
     def typecheck(self, space, w_obj):
         if not space.is_true(space.isinstance(w_obj, self.w_cls)):
             raise operationerrfmt(space.w_TypeError,
@@ -552,7 +552,7 @@
                                   self.name,
                                   self.w_cls.name,
                                   space.type(w_obj).getname(space))
-    
+
     def descr_member_get(self, space, w_obj, w_w_cls=None):
         """member.__get__(obj[, type]) -> value
         Read the slot 'member' of the given 'obj'."""
@@ -565,13 +565,13 @@
                 raise OperationError(space.w_AttributeError,
                                      space.wrap(self.name)) # XXX better message
             return w_result
-    
+
     def descr_member_set(self, space, w_obj, w_value):
         """member.__set__(obj, value)
         Write into the slot 'member' of the given 'obj'."""
         self.typecheck(space, w_obj)
         w_obj.setslotvalue(self.index, w_value)
-    
+
     def descr_member_del(self, space, w_obj):
         """member.__delete__(obj)
         Delete the value of the slot 'member' from the given 'obj'."""
@@ -803,15 +803,16 @@
     func_dict = getset_func_dict,
     func_defaults = getset_func_defaults,
     func_globals = interp_attrproperty_w('w_func_globals', cls=Function),
-    func_closure = GetSetProperty( Function.fget_func_closure ),
+    func_closure = GetSetProperty(Function.fget_func_closure),
     __code__ = getset_func_code,
     __doc__ = getset_func_doc,
     __name__ = getset_func_name,
     __dict__ = getset_func_dict,
     __defaults__ = getset_func_defaults,
+    __globals__ = interp_attrproperty_w('w_func_globals', cls=Function),
     __module__ = getset___module__,
     __weakref__ = make_weakref_descr(Function),
-    )
+)
 Function.typedef.acceptable_as_base_class = False
 
 Method.typedef = TypeDef(
diff --git a/pypy/jit/backend/arm/test/test_ztranslation.py b/pypy/jit/backend/arm/test/test_ztranslation.py
--- a/pypy/jit/backend/arm/test/test_ztranslation.py
+++ b/pypy/jit/backend/arm/test/test_ztranslation.py
@@ -3,12 +3,14 @@
 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
 from pypy.jit.codewriter.policy import StopAtXPolicy
 from pypy.translator.translator import TranslationContext
 from pypy.config.translationoption import DEFL_GC
+from pypy.rlib import rgc
 from pypy.jit.backend.arm.test.support import skip_unless_run_slow_tests
 skip_unless_run_slow_tests()
 
@@ -173,6 +175,24 @@
         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 TestTranslationRemoveTypePtrARM(CCompiledMixin):
     CPUClass = getcpuclass()
 
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
@@ -97,6 +97,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'),
@@ -1528,6 +1529,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
@@ -585,6 +590,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/model.py b/pypy/jit/backend/model.py
--- a/pypy/jit/backend/model.py
+++ b/pypy/jit/backend/model.py
@@ -60,6 +60,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()
@@ -997,6 +998,24 @@
             getattr(self.mc, asmop)(arglocs[0], arglocs[1])
         return genop_binary
 
+    def _binaryop_or_lea(asmop, is_add):
+        def genop_binary_or_lea(self, op, arglocs, result_loc):
+            # use a regular ADD or SUB if result_loc is arglocs[0],
+            # and a LEA only if different.
+            if result_loc is arglocs[0]:
+                getattr(self.mc, asmop)(arglocs[0], arglocs[1])
+            else:
+                loc = arglocs[0]
+                argloc = arglocs[1]
+                assert isinstance(loc, RegLoc)
+                assert isinstance(argloc, ImmedLoc)
+                assert isinstance(result_loc, RegLoc)
+                delta = argloc.value
+                if not is_add:    # subtraction
+                    delta = -delta
+                self.mc.LEA_rm(result_loc.value, (loc.value, delta))
+        return genop_binary_or_lea
+
     def _cmpop(cond, rev_cond):
         def genop_cmp(self, op, arglocs, result_loc):
             rl = result_loc.lowest8bits()
@@ -1223,8 +1242,8 @@
 
     genop_int_neg = _unaryop("NEG")
     genop_int_invert = _unaryop("NOT")
-    genop_int_add = _binaryop("ADD", True)
-    genop_int_sub = _binaryop("SUB")
+    genop_int_add = _binaryop_or_lea("ADD", True)
+    genop_int_sub = _binaryop_or_lea("SUB", False)
     genop_int_mul = _binaryop("IMUL", True)
     genop_int_and = _binaryop("AND", True)
     genop_int_or  = _binaryop("OR", True)
@@ -1374,6 +1393,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()
@@ -1705,15 +1729,15 @@
                             guard_op.getopname())
 
     def genop_guard_int_add_ovf(self, op, guard_op, guard_token, arglocs, result_loc):
-        self.genop_int_add(op, arglocs, result_loc)
+        self.mc.ADD(arglocs[0], arglocs[1])
         return self._gen_guard_overflow(guard_op, guard_token)
 
     def genop_guard_int_sub_ovf(self, op, guard_op, guard_token, arglocs, result_loc):
-        self.genop_int_sub(op, arglocs, result_loc)
+        self.mc.SUB(arglocs[0], arglocs[1])
         return self._gen_guard_overflow(guard_op, guard_token)
 
     def genop_guard_int_mul_ovf(self, op, guard_op, guard_token, arglocs, result_loc):
-        self.genop_int_mul(op, arglocs, result_loc)
+        self.mc.IMUL(arglocs[0], arglocs[1])
         return self._gen_guard_overflow(guard_op, guard_token)
 
     def genop_guard_guard_false(self, ign_1, guard_op, guard_token, locs, ign_2):
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
@@ -26,6 +26,7 @@
      TempBox, compute_vars_longevity, is_comparison_or_ovf_op
 from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE
 from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64, MY_COPY_OF_REGS
+from pypy.jit.backend.x86 import rx86
 from pypy.rlib.rarithmetic import r_longlong
 
 class X86RegisterManager(RegisterManager):
@@ -552,9 +553,31 @@
         loc, argloc = self._consider_binop_part(op)
         self.Perform(op, [loc, argloc], loc)
 
-    consider_int_add = _consider_binop
+    def _consider_lea(self, op, loc):
+        argloc = self.loc(op.getarg(1))
+        self.rm.possibly_free_var(op.getarg(0))
+        resloc = self.force_allocate_reg(op.result)
+        self.Perform(op, [loc, argloc], resloc)
+
+    def consider_int_add(self, op):
+        loc = self.loc(op.getarg(0))
+        y = op.getarg(1)
+        if (isinstance(loc, RegLoc) and
+            isinstance(y, ConstInt) and rx86.fits_in_32bits(y.value)):
+            self._consider_lea(op, loc)
+        else:
+            self._consider_binop(op)
+
+    def consider_int_sub(self, op):
+        loc = self.loc(op.getarg(0))
+        y = op.getarg(1)
+        if (isinstance(loc, RegLoc) and
+            isinstance(y, ConstInt) and rx86.fits_in_32bits(-y.value)):
+            self._consider_lea(op, loc)
+        else:
+            self._consider_binop(op)
+
     consider_int_mul = _consider_binop
-    consider_int_sub = _consider_binop
     consider_int_and = _consider_binop
     consider_int_or  = _consider_binop
     consider_int_xor = _consider_binop
@@ -1110,6 +1133,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/backend/x86/tool/test/test_viewcode.py b/pypy/jit/backend/x86/tool/test/test_viewcode.py
--- a/pypy/jit/backend/x86/tool/test/test_viewcode.py
+++ b/pypy/jit/backend/x86/tool/test/test_viewcode.py
@@ -1,5 +1,10 @@
 from cStringIO import StringIO
 from pypy.jit.backend.x86.tool.viewcode import format_code_dump_with_labels
+from pypy.jit.backend.x86.tool.viewcode import find_objdump
+import os
+import py
+import tempfile
+from pypy.tool.udir import udir
 
 def test_format_code_dump_with_labels():
     lines = StringIO("""
@@ -53,3 +58,16 @@
     lines = format_code_dump_with_labels(0xAA00, lines, label_list=None)
     out = ''.join(lines)
     assert out.strip() == input
+
+def test_find_objdump():
+    old = os.environ['PATH']
+    os.environ['PATH'] = ''
+    py.test.raises(find_objdump)
+
+    #
+    path = udir.join('objdump')
+    print >>path, 'hello world'
+    os.environ['PATH'] = path.dirname
+    assert find_objdump() == 'objdump'
+    #
+    os.environ['PATH'] = old
diff --git a/pypy/jit/backend/x86/tool/viewcode.py b/pypy/jit/backend/x86/tool/viewcode.py
--- a/pypy/jit/backend/x86/tool/viewcode.py
+++ b/pypy/jit/backend/x86/tool/viewcode.py
@@ -8,9 +8,9 @@
     ./viewcode.py log               # also includes a pygame viewer
 """
 
-import autopath
 import new
 import operator
+import os
 import py
 import re
 import sys
@@ -36,6 +36,17 @@
 if sys.platform == "win32":
     pass   # lots more in Psyco
 
+def find_objdump():
+    exe = ('objdump', 'gobjdump')
+    path = os.environ['PATH'].split(os.pathsep)
+    for e in exe:
+        for p in path:
+            path_to = os.path.join(p, e)
+            if not os.path.exists(path_to):
+                continue
+            return e
+    raise AssertionError('(g)objdump was not found in PATH')
+
 def machine_code_dump(data, originaddr, backend_name, label_list=None):
     objdump_backend_option = {
         'x86': 'i386',
@@ -43,7 +54,8 @@
         'x86_64': 'x86-64',
         'i386': 'i386',
     }
-    objdump = ('objdump -M %(backend)s -b binary -m i386 '
+    cmd = find_objdump()
+    objdump = ('%(command)s -M %(backend)s -b binary -m i386 '
                '--disassembler-options=intel-mnemonics '
                '--adjust-vma=%(origin)d -D %(file)s')
     #
@@ -51,6 +63,7 @@
     f.write(data)
     f.close()
     p = subprocess.Popen(objdump % {
+        'command': cmd,
         'file': tmpfile,
         'origin': originaddr,
         'backend': objdump_backend_option[backend_name],
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
@@ -63,11 +63,10 @@
             contains_loop = contains_loop and not getattr(
                     func, '_jit_unroll_safe_', False)
 
-        unsupported = contains_unsupported_variable_type(graph,
+        res = see_function and not contains_unsupported_variable_type(graph,
                             self.supports_floats,
                             self.supports_longlong,
                             self.supports_singlefloats)
-        res = see_function and not unsupported
         if res and contains_loop:
             self.unsafe_loopy_graphs.add(graph)
         res = res and not contains_loop
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/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_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -3797,6 +3797,7 @@
         assert res == 3
 
     def test_float_bytes(self):
+        from pypy.rlib.rfloat import isnan
         def f(n):
             ll = float2longlong(n)
             return longlong2float(ll)
@@ -3804,7 +3805,7 @@
         for x in [2.5, float("nan"), -2.5, float("inf")]:
             # There are tests elsewhere to verify the correctness of this.
             res = self.interp_operations(f, [x])
-            assert res == x or math.isnan(x) and math.isnan(res)
+            assert res == x or isnan(x) and isnan(res)
 
 
 class TestLLtype(BaseLLtypeTests, LLJitMixin):
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_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/__pypy__/interp_time.py b/pypy/module/__pypy__/interp_time.py
--- a/pypy/module/__pypy__/interp_time.py
+++ b/pypy/module/__pypy__/interp_time.py
@@ -1,5 +1,5 @@
 from __future__ import with_statement
-import os
+import sys
 
 from pypy.interpreter.error import exception_from_errno
 from pypy.interpreter.gateway import unwrap_spec
@@ -7,10 +7,11 @@
 from pypy.rpython.tool import rffi_platform
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
-if os.name == 'nt':
+if sys.platform == 'linux2':
+    libraries = ["rt"]
+else:
     libraries = []
-else:
-    libraries = ["rt"]
+
 
 class CConfig:
     _compilation_info_ = ExternalCompilationInfo(
diff --git a/pypy/module/_hashlib/interp_hashlib.py b/pypy/module/_hashlib/interp_hashlib.py
--- a/pypy/module/_hashlib/interp_hashlib.py
+++ b/pypy/module/_hashlib/interp_hashlib.py
@@ -96,6 +96,9 @@
         block_size = rffi.getintfield(digest_type, 'c_block_size')
         return space.wrap(block_size)
 
+    def get_name(self, space):
+        return space.wrap(self.name)
+
     def _digest(self, space):
         with lltype.scoped_alloc(ropenssl.EVP_MD_CTX.TO) as ctx:
             with self.lock:
@@ -118,6 +121,7 @@
     digest_size=GetSetProperty(W_Hash.get_digest_size),
     digestsize=GetSetProperty(W_Hash.get_digest_size),
     block_size=GetSetProperty(W_Hash.get_block_size),
+    name=GetSetProperty(W_Hash.get_name),
     )
 W_Hash.acceptable_as_base_class = False
 
diff --git a/pypy/module/_hashlib/test/test_hashlib.py b/pypy/module/_hashlib/test/test_hashlib.py
--- a/pypy/module/_hashlib/test/test_hashlib.py
+++ b/pypy/module/_hashlib/test/test_hashlib.py
@@ -20,6 +20,7 @@
                                     'sha512': 64,
                                     }.items():
             h = hashlib.new(name)
+            assert h.name == name
             assert h.digest_size == expected_size
             assert h.digestsize == expected_size
             #
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/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
@@ -227,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
@@ -346,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):
@@ -368,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)
@@ -459,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)
@@ -471,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):
@@ -487,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):
@@ -602,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)
@@ -648,7 +663,7 @@
 
     def array_copy__Array(space, self):
         w_a = mytype.w_class(self.space)
-        w_a.setlen(self.len)
+        w_a.setlen(self.len, overallocate=False)
         rffi.c_memcpy(
             rffi.cast(rffi.VOIDP, w_a.buffer),
             rffi.cast(rffi.VOIDP, self.buffer),
diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -890,6 +890,54 @@
         a[::-1] = a
         assert a == self.array('b', [3, 2, 1, 0])
 
+    def test_array_multiply(self):
+        a = self.array('b', [0])
+        b = a * 13
+        assert b[12] == 0
+        b = 13 * a
+        assert b[12] == 0
+        a *= 13
+        assert a[12] == 0
+        a = self.array('b', [1])
+        b = a * 13
+        assert b[12] == 1
+        b = 13 * a
+        assert b[12] == 1
+        a *= 13
+        assert a[12] == 1
+        a = self.array('i', [0])
+        b = a * 13
+        assert b[12] == 0
+        b = 13 * a
+        assert b[12] == 0
+        a *= 13
+        assert a[12] == 0
+        a = self.array('i', [1])
+        b = a * 13
+        assert b[12] == 1
+        b = 13 * a
+        assert b[12] == 1
+        a *= 13
+        assert a[12] == 1
+        a = self.array('i', [0, 0])
+        b = a * 13
+        assert len(b) == 26
+        assert b[22] == 0
+        b = 13 * a
+        assert len(b) == 26
+        assert b[22] == 0
+        a *= 13
+        assert a[22] == 0
+        assert len(a) == 26
+        a = self.array('f', [-0.0])
+        b = a * 13
+        assert len(b) == 13
+        assert str(b[12]) == "-0.0"
+        a = self.array('d', [-0.0])
+        b = a * 13
+        assert len(b) == 13
+        assert str(b[12]) == "-0.0"
+
 
 class AppTestArrayBuiltinShortcut(AppTestArray):
     OPTIONS = {'objspace.std.builtinshortcut': True}
diff --git a/pypy/module/cppyy/__init__.py b/pypy/module/cppyy/__init__.py
--- a/pypy/module/cppyy/__init__.py
+++ b/pypy/module/cppyy/__init__.py
@@ -1,7 +1,9 @@
 from pypy.interpreter.mixedmodule import MixedModule
 
 class Module(MixedModule):
-    """    """
+    "This module provides runtime bindings to C++ code for which reflection\n\
+    info has been generated. Current supported back-ends are Reflex and CINT.\n\
+    See http://doc.pypy.org/en/latest/cppyy.html for full details."
 
     interpleveldefs = {
         '_load_dictionary'       : 'interp_cppyy.load_dictionary',
@@ -20,3 +22,12 @@
         'load_reflection_info'   : 'pythonify.load_reflection_info',
         'add_pythonization'      : 'pythonify.add_pythonization',
     }
+
+    def __init__(self, space, *args):
+        "NOT_RPYTHON"
+        MixedModule.__init__(self, space, *args)
+
+        # pythonization functions may be written in RPython, but the interp2app
+        # code generation is not, so give it a chance to run now
+        from pypy.module.cppyy import capi
+        capi.register_pythonizations(space)
diff --git a/pypy/module/cppyy/capi/__init__.py b/pypy/module/cppyy/capi/__init__.py
--- a/pypy/module/cppyy/capi/__init__.py
+++ b/pypy/module/cppyy/capi/__init__.py
@@ -4,7 +4,10 @@
 import reflex_capi as backend
 #import cint_capi as backend
 
-identify = backend.identify
+identify  = backend.identify
+pythonize = backend.pythonize
+register_pythonizations = backend.register_pythonizations
+
 ts_reflect = backend.ts_reflect
 ts_call    = backend.ts_call
 ts_memory  = backend.ts_memory
@@ -23,6 +26,8 @@
 C_NULL_OBJECT = rffi.cast(C_OBJECT, _C_OPAQUE_NULL)
 
 C_METHOD = _C_OPAQUE_PTR
+C_INDEX = rffi.LONG
+WLAVC_INDEX = rffi.LONG
 
 C_METHPTRGETTER = lltype.FuncType([C_OBJECT], rffi.VOIDP)
 C_METHPTRGETTER_PTR = lltype.Ptr(C_METHPTRGETTER)
@@ -37,6 +42,20 @@
 c_load_dictionary = backend.c_load_dictionary
 
 # name to opaque C++ scope representation ------------------------------------
+_c_num_scopes = rffi.llexternal(
+    "cppyy_num_scopes",
+    [C_SCOPE], rffi.INT,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_num_scopes(cppscope):
+    return _c_num_scopes(cppscope.handle)
+_c_scope_name = rffi.llexternal(
+    "cppyy_scope_name",
+    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    compilation_info = backend.eci)
+def c_scope_name(cppscope, iscope):
+    return charp2str_free(_c_scope_name(cppscope.handle, iscope))
+
 _c_resolve_name = rffi.llexternal(
     "cppyy_resolve_name",
     [rffi.CCHARP], rffi.CCHARP,
@@ -93,7 +112,7 @@
     compilation_info=backend.eci)
 c_call_b = rffi.llexternal(
     "cppyy_call_b",
-    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT,
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.UCHAR,
     threadsafe=ts_call,
     compilation_info=backend.eci)
 c_call_c = rffi.llexternal(
@@ -123,7 +142,7 @@
     compilation_info=backend.eci)
 c_call_f = rffi.llexternal(
     "cppyy_call_f",
-    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE,
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.FLOAT,
     threadsafe=ts_call,
     compilation_info=backend.eci)
 c_call_d = rffi.llexternal(
@@ -148,23 +167,22 @@
     [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)
+def c_call_o(method, cppobj, nargs, args, cppclass):
+    return _c_call_o(method, cppobj, nargs, args, cppclass.handle)
 
 _c_get_methptr_getter = rffi.llexternal(
     "cppyy_get_methptr_getter",
-    [C_SCOPE, rffi.INT], C_METHPTRGETTER_PTR,
+    [C_SCOPE, C_INDEX], 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)
+def c_get_methptr_getter(cppscope, index):
+    return _c_get_methptr_getter(cppscope.handle, index)
 
 # handling of function argument buffer ---------------------------------------
 c_allocate_function_args = rffi.llexternal(
@@ -236,7 +254,6 @@
     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,
@@ -269,87 +286,103 @@
     compilation_info=backend.eci)
 def c_num_methods(cppscope):
     return _c_num_methods(cppscope.handle)
+_c_method_index_at = rffi.llexternal(
+    "cppyy_method_index_at",
+    [C_SCOPE, rffi.INT], C_INDEX,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_index_at(cppscope, imethod):
+    return _c_method_index_at(cppscope.handle, imethod)
+_c_method_index_from_name = rffi.llexternal(
+    "cppyy_method_index_from_name",
+    [C_SCOPE, rffi.CCHARP], C_INDEX,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_method_index_from_name(cppscope, name):
+    return _c_method_index_from_name(cppscope.handle, name)
+
 _c_method_name = rffi.llexternal(
     "cppyy_method_name",
-    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    [C_SCOPE, C_INDEX], 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))
+def c_method_name(cppscope, index):
+    return charp2str_free(_c_method_name(cppscope.handle, index))
 _c_method_result_type = rffi.llexternal(
     "cppyy_method_result_type",
-    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    [C_SCOPE, C_INDEX], 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))
+def c_method_result_type(cppscope, index):
+    return charp2str_free(_c_method_result_type(cppscope.handle, index))
 _c_method_num_args = rffi.llexternal(
     "cppyy_method_num_args",
-    [C_SCOPE, rffi.INT], rffi.INT,
+    [C_SCOPE, C_INDEX], 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)
+def c_method_num_args(cppscope, index):
+    return _c_method_num_args(cppscope.handle, index)
 _c_method_req_args = rffi.llexternal(
     "cppyy_method_req_args",
-    [C_SCOPE, rffi.INT], rffi.INT,
+    [C_SCOPE, C_INDEX], 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)
+def c_method_req_args(cppscope, index):
+    return _c_method_req_args(cppscope.handle, index)
 _c_method_arg_type = rffi.llexternal(
     "cppyy_method_arg_type",
-    [C_SCOPE, rffi.INT, rffi.INT], rffi.CCHARP,
+    [C_SCOPE, C_INDEX, 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))
+def c_method_arg_type(cppscope, index, arg_index):
+    return charp2str_free(_c_method_arg_type(cppscope.handle, index, arg_index))
 _c_method_arg_default = rffi.llexternal(
     "cppyy_method_arg_default",
-    [C_SCOPE, rffi.INT, rffi.INT], rffi.CCHARP,
+    [C_SCOPE, C_INDEX, 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))
+def c_method_arg_default(cppscope, index, arg_index):
+    return charp2str_free(_c_method_arg_default(cppscope.handle, index, arg_index))
 _c_method_signature = rffi.llexternal(
     "cppyy_method_signature",
-    [C_SCOPE, rffi.INT], rffi.CCHARP,
+    [C_SCOPE, C_INDEX], 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)
+def c_method_signature(cppscope, index):
+    return charp2str_free(_c_method_signature(cppscope.handle, index))
 
 _c_get_method = rffi.llexternal(
     "cppyy_get_method",
-    [C_SCOPE, rffi.INT], C_METHOD,
+    [C_SCOPE, C_INDEX], C_METHOD,
     threadsafe=ts_reflect,
     compilation_info=backend.eci)
-def c_get_method(cppscope, method_index):
-    return _c_get_method(cppscope.handle, method_index)
+def c_get_method(cppscope, index):
+    return _c_get_method(cppscope.handle, index)
+_c_get_global_operator = rffi.llexternal(
+    "cppyy_get_global_operator",
+    [C_SCOPE, C_SCOPE, C_SCOPE, rffi.CCHARP], WLAVC_INDEX,
+    threadsafe=ts_reflect,
+    compilation_info=backend.eci)
+def c_get_global_operator(nss, lc, rc, op):
+    if nss is not None:
+        return _c_get_global_operator(nss.handle, lc.handle, rc.handle, op)
+    return rffi.cast(WLAVC_INDEX, -1)
 
 # method properties ----------------------------------------------------------
 _c_is_constructor = rffi.llexternal(
     "cppyy_is_constructor",
-    [C_TYPE, rffi.INT], rffi.INT,
+    [C_TYPE, C_INDEX], rffi.INT,
     threadsafe=ts_reflect,
     compilation_info=backend.eci)
-def c_is_constructor(cppclass, method_index):
-    return _c_is_constructor(cppclass.handle, method_index)
+def c_is_constructor(cppclass, index):
+    return _c_is_constructor(cppclass.handle, index)
 _c_is_staticmethod = rffi.llexternal(
     "cppyy_is_staticmethod",
-    [C_TYPE, rffi.INT], rffi.INT,
+    [C_TYPE, C_INDEX], rffi.INT,
     threadsafe=ts_reflect,
     compilation_info=backend.eci)
-def c_is_staticmethod(cppclass, method_index):
-    return _c_is_staticmethod(cppclass.handle, method_index)
+def c_is_staticmethod(cppclass, index):
+    return _c_is_staticmethod(cppclass.handle, index)
 
 # data member reflection information -----------------------------------------
 _c_num_datamembers = rffi.llexternal(
diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py
--- a/pypy/module/cppyy/capi/cint_capi.py
+++ b/pypy/module/cppyy/capi/cint_capi.py
@@ -1,9 +1,17 @@
-import py, os
+import py, os, sys
+
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef
+from pypy.interpreter.baseobjspace import Wrappable
 
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.rpython.lltypesystem import rffi
 from pypy.rlib import libffi, rdynload
 
+from pypy.module.itertools import interp_itertools
+
+
 __all__ = ['identify', 'eci', 'c_load_dictionary']
 
 pkgpath = py.path.local(__file__).dirpath().join(os.pardir)
@@ -61,3 +69,168 @@
         err = rdynload.dlerror()
         raise rdynload.DLOpenError(err)
     return libffi.CDLL(name)       # should return handle to already open file
+
+
+# CINT-specific pythonizations ===============================================
+
+### TTree --------------------------------------------------------------------
+_ttree_Branch = rffi.llexternal(
+    "cppyy_ttree_Branch",
+    [rffi.VOIDP, rffi.CCHARP, rffi.CCHARP, rffi.VOIDP, rffi.INT, rffi.INT], rffi.LONG,
+    threadsafe=False,
+    compilation_info=eci)
+
+ at unwrap_spec(args_w='args_w')
+def ttree_Branch(space, w_self, args_w):
+    """Pythonized version of TTree::Branch(): takes proxy objects and by-passes
+    the CINT-manual layer."""
+
+    from pypy.module.cppyy import interp_cppyy
+    tree_class = interp_cppyy.scope_byname(space, "TTree")
+
+    # sigs to modify (and by-pass CINT):
+    #  1. (const char*, const char*, T**,               Int_t=32000, Int_t=99)
+    #  2. (const char*, T**,                            Int_t=32000, Int_t=99)
+    argc = len(args_w)
+
+    # basic error handling of wrong arguments is best left to the original call,
+    # so that error messages etc. remain consistent in appearance: the following
+    # block may raise TypeError or IndexError to break out anytime
+
+    try:
+        if argc < 2 or 5 < argc:
+            raise TypeError("wrong number of arguments")
+
+        tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self, can_be_None=True)
+        if (tree is None) or (tree.cppclass != tree_class):
+            raise TypeError("not a TTree")
+
+        # first argument must always always be cont char*
+        branchname = space.str_w(args_w[0])
+
+        # if args_w[1] is a classname, then case 1, else case 2
+        try:
+            classname = space.str_w(args_w[1])
+            addr_idx  = 2
+            w_address = args_w[addr_idx]
+        except OperationError:
+            addr_idx  = 1
+            w_address = args_w[addr_idx]
+
+        bufsize, splitlevel = 32000, 99
+        if addr_idx+1 < argc: bufsize = space.c_int_w(args_w[addr_idx+1])
+        if addr_idx+2 < argc: splitlevel = space.c_int_w(args_w[addr_idx+2])
+
+        # now retrieve the W_CPPInstance and build other stub arguments
+        space = tree.space    # holds the class cache in State
+        cppinstance = space.interp_w(interp_cppyy.W_CPPInstance, w_address)
+        address = rffi.cast(rffi.VOIDP, cppinstance.get_rawobject())
+        klassname = cppinstance.cppclass.full_name()
+        vtree = rffi.cast(rffi.VOIDP, tree.get_rawobject())
+
+        # call the helper stub to by-pass CINT
+        vbranch = _ttree_Branch(vtree, branchname, klassname, address, bufsize, splitlevel)
+        branch_class = interp_cppyy.scope_byname(space, "TBranch")
+        w_branch = interp_cppyy.wrap_cppobject(
+            space, space.w_None, branch_class, vbranch, isref=False, python_owns=False)
+        return w_branch
+    except (OperationError, TypeError, IndexError), e:
+        pass
+
+    # return control back to the original, unpythonized overload
+    return tree_class.get_overload("Branch").call(w_self, args_w)
+
+def activate_branch(space, w_branch):
+    w_branches = space.call_method(w_branch, "GetListOfBranches")
+    for i in range(space.int_w(space.call_method(w_branches, "GetEntriesFast"))):
+        w_b = space.call_method(w_branches, "At", space.wrap(i))
+        activate_branch(space, w_b)
+    space.call_method(w_branch, "SetStatus", space.wrap(1))
+    space.call_method(w_branch, "ResetReadEntry")
+
+ at unwrap_spec(args_w='args_w')
+def ttree_getattr(space, w_self, args_w):
+    """Specialized __getattr__ for TTree's that allows switching on/off the
+    reading of individual branchs."""
+
+    from pypy.module.cppyy import interp_cppyy
+    tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self)
+
+    # setup branch as a data member and enable it for reading
+    space = tree.space            # holds the class cache in State
+    w_branch = space.call_method(w_self, "GetBranch", args_w[0])
+    w_klassname = space.call_method(w_branch, "GetClassName")
+    klass = interp_cppyy.scope_byname(space, space.str_w(w_klassname))
+    w_obj = klass.construct()
+    #space.call_method(w_branch, "SetStatus", space.wrap(1)) 
+    activate_branch(space, w_branch)
+    space.call_method(w_branch, "SetObject", w_obj)
+    space.call_method(w_branch, "GetEntry", space.wrap(0))
+    space.setattr(w_self, args_w[0], w_obj)
+    return w_obj
+
+class W_TTreeIter(Wrappable):
+    def __init__(self, space, w_tree):
+
+        from pypy.module.cppyy import interp_cppyy
+        tree = space.interp_w(interp_cppyy.W_CPPInstance, w_tree)
+        self.tree = tree.get_cppthis(tree.cppclass)
+        self.w_tree = w_tree
+
+        self.getentry = tree.cppclass.get_overload("GetEntry").functions[0]
+        self.current  = 0
+        self.maxentry = space.int_w(space.call_method(w_tree, "GetEntriesFast"))
+
+        space = self.space = tree.space          # holds the class cache in State
+        space.call_method(w_tree, "SetBranchStatus", space.wrap("*"), space.wrap(0))
+
+    def iter_w(self):
+        return self.space.wrap(self)
+
+    def next_w(self):
+        if self.current == self.maxentry:
+            raise OperationError(self.space.w_StopIteration, self.space.w_None)
+        # TODO: check bytes read?
+        self.getentry.call(self.tree, [self.space.wrap(self.current)])
+        self.current += 1 
+        return self.w_tree
+
+W_TTreeIter.typedef = TypeDef(
+    'TTreeIter',
+    __iter__ = interp2app(W_TTreeIter.iter_w),
+    next = interp2app(W_TTreeIter.next_w),
+)
+
+def ttree_iter(space, w_self):
+    """Allow iteration over TTree's. Also initializes branch data members and
+    sets addresses, if needed."""
+    w_treeiter = W_TTreeIter(space, w_self)
+    return w_treeiter
+
+# setup pythonizations for later use at run-time
+_pythonizations = {}
+def register_pythonizations(space):
+    "NOT_RPYTHON"
+
+    ### TTree
+    _pythonizations['ttree_Branch']  = space.wrap(interp2app(ttree_Branch))
+    _pythonizations['ttree_iter']    = space.wrap(interp2app(ttree_iter))
+    _pythonizations['ttree_getattr'] = space.wrap(interp2app(ttree_getattr))
+
+# callback coming in when app-level bound classes have been created
+def pythonize(space, name, w_pycppclass):
+
+    if name == 'TFile':
+        space.setattr(w_pycppclass, space.wrap("__getattr__"),
+                      space.getattr(w_pycppclass, space.wrap("Get")))
+
+    elif name == 'TTree':
+        space.setattr(w_pycppclass, space.wrap("_unpythonized_Branch"),
+                      space.getattr(w_pycppclass, space.wrap("Branch")))
+        space.setattr(w_pycppclass, space.wrap("Branch"), _pythonizations["ttree_Branch"])
+        space.setattr(w_pycppclass, space.wrap("__iter__"), _pythonizations["ttree_iter"])
+        space.setattr(w_pycppclass, space.wrap("__getattr__"), _pythonizations["ttree_getattr"])
+
+    elif name[0:8] == "TVectorT":    # TVectorT<> template
+        space.setattr(w_pycppclass, space.wrap("__len__"),
+                      space.getattr(w_pycppclass, space.wrap("GetNoElements")))
diff --git a/pypy/module/cppyy/capi/reflex_capi.py b/pypy/module/cppyy/capi/reflex_capi.py
--- a/pypy/module/cppyy/capi/reflex_capi.py
+++ b/pypy/module/cppyy/capi/reflex_capi.py
@@ -41,3 +41,12 @@
 
 def c_load_dictionary(name):
     return libffi.CDLL(name)
+
+
+# Reflex-specific pythonizations
+def register_pythonizations(space):
+    "NOT_RPYTHON"
+    pass
+
+def pythonize(space, name, w_pycppclass):
+    pass
diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py
--- a/pypy/module/cppyy/converter.py
+++ b/pypy/module/cppyy/converter.py
@@ -4,12 +4,21 @@
 
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rlib.rarithmetic import r_singlefloat
-from pypy.rlib import jit, libffi, clibffi, rfloat
+from pypy.rlib import 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
+from pypy.module.cppyy import helper, capi, ffitypes
+
+# Converter objects are used to translate between RPython and C++. They are
+# defined by the type name for which they provide conversion. Uses are for
+# function arguments, as well as for read and write access to data members.
+# All type conversions are fully checked.
+#
+# Converter instances are greated by get_converter(<type name>), see below.
+# The name given should be qualified in case there is a specialised, exact
+# match for the qualified type.
 
 
 def get_rawobject(space, w_obj):
@@ -38,6 +47,24 @@
         return rawobject
     return capi.C_NULL_OBJECT
 
+def get_rawbuffer(space, w_obj):
+    try:
+        buf = space.buffer_w(w_obj)
+        return rffi.cast(rffi.VOIDP, buf.get_raw_address())
+    except Exception:
+        pass
+    # special case: allow integer 0 as NULL
+    try:
+        buf = space.int_w(w_obj)
+        if buf == 0:
+            return rffi.cast(rffi.VOIDP, 0)
+    except Exception:
+        pass
+    # special case: allow None as NULL
+    if space.is_true(space.is_(w_obj, space.w_None)):
+        return rffi.cast(rffi.VOIDP, 0)
+    raise TypeError("not an addressable buffer")
+
 
 class TypeConverter(object):
     _immutable_ = True
@@ -59,7 +86,7 @@
         return fieldptr
 
     def _is_abstract(self, space):
-        raise OperationError(space.w_TypeError, space.wrap("no converter available"))
+        raise OperationError(space.w_TypeError, space.wrap("no converter available for '%s'" % self.name))
 
     def convert_argument(self, space, w_obj, address, call_local):
         self._is_abstract(space)
@@ -135,6 +162,20 @@
     def __init__(self, space, array_size):
         self.size = sys.maxint
 
+    def convert_argument(self, space, w_obj, address, call_local):
+        w_tc = space.findattr(w_obj, space.wrap('typecode'))
+        if w_tc is not None and space.str_w(w_tc) != self.typecode:
+            msg = "expected %s pointer type, but received %s" % (self.typecode, space.str_w(w_tc))
+            raise OperationError(space.w_TypeError, space.wrap(msg))
+        x = rffi.cast(rffi.LONGP, address)
+        try:
+            x[0] = rffi.cast(rffi.LONG, get_rawbuffer(space, w_obj))
+        except TypeError:
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("raw buffer interface not supported"))
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'o'
+
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         # read access, so no copy needed
         address_value = self._get_raw_address(space, w_obj, offset)
@@ -218,16 +259,8 @@
                              space.wrap('no converter available for type "%s"' % self.name))
 
 
-class BoolConverter(TypeConverter):
+class BoolConverter(ffitypes.typeid(bool), 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)
@@ -250,26 +283,8 @@
         else:
             address[0] = '\x00'
 
-class CharConverter(TypeConverter):
+class CharConverter(ffitypes.typeid(rffi.CHAR), 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)
@@ -286,156 +301,8 @@
         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):
+class FloatConverter(ffitypes.typeid(rffi.FLOAT), FloatTypeConverterMixin, 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:
@@ -444,9 +311,6 @@
             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)
@@ -461,12 +325,8 @@
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
-class DoubleConverter(FloatTypeConverterMixin, TypeConverter):
+class DoubleConverter(ffitypes.typeid(rffi.DOUBLE), 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:
@@ -474,9 +334,6 @@
         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
@@ -507,9 +364,12 @@
 
     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'
+        try:
+            x[0] = get_rawbuffer(space, w_obj)
+        except TypeError:
+            x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+        ba[capi.c_function_arg_typeoffset()] = 'o'
 
     def convert_argument_libffi(self, space, w_obj, argchain, call_local):
         argchain.arg(get_rawobject(space, w_obj))
@@ -519,27 +379,26 @@
     uses_local = True
 
     def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.VOIDPP, address)
+        ba = rffi.cast(rffi.CCHARP, address)
         r = rffi.cast(rffi.VOIDPP, call_local)
-        r[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
-        x = rffi.cast(rffi.VOIDPP, address)
+        try:
+            r[0] = get_rawbuffer(space, w_obj)
+        except TypeError:
+            r[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
         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])
+        try:
+            set_rawobject(space, w_obj, r[0])
+        except OperationError:
+            pass             # no set on buffer/array/None
 
-class VoidPtrRefConverter(TypeConverter):
+class VoidPtrRefConverter(VoidPtrPtrConverter):
     _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'
-
+    uses_local = True
 
 class InstancePtrConverter(TypeConverter):
     _immutable_ = True
@@ -631,13 +490,13 @@
 
     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
+            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)
+            arg = InstanceConverter._unwrap_object(self, space, w_obj)
+            return capi.c_stdstring2stdstring(arg)
 
     def to_memory(self, space, w_obj, w_value, offset):
         try:
@@ -672,7 +531,7 @@
         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);
+        x[0] = rffi.cast(rffi.VOIDP, ref)
         ba = rffi.cast(rffi.CCHARP, address)
         ba[capi.c_function_arg_typeoffset()] = 'a'
 
@@ -719,7 +578,7 @@
 
     #   2) match of decorated, unqualified type
     compound = helper.compound(name)
-    clean_name = helper.clean_type(name)
+    clean_name = capi.c_resolve_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)
@@ -743,8 +602,8 @@
         elif compound == "":
             return InstanceConverter(space, cppclass)
     elif capi.c_is_enum(clean_name):
-        return UnsignedIntConverter(space, default)
-    
+        return _converters['unsigned'](space, default)
+
     #   5) void converter, which fails on use
     #
     # return a void converter here, so that the class can be build even
@@ -754,59 +613,96 @@
 
 _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*"]
 
+# add basic (builtin) converters
+def _build_basic_converters():
+    "NOT_RPYTHON"
+    # signed types (use strtoll in setting of default in __init__)
+    type_info = (
+        (rffi.SHORT,      ("short", "short int")),
+        (rffi.INT,        ("int",)),
+    )
+
+    # constref converters exist only b/c the stubs take constref by value, whereas
+    # libffi takes them by pointer (hence it needs the fast-path in testing); note
+    # that this is list is not complete, as some classes are specialized
+
+    for c_type, names in type_info:
+        class BasicConverter(ffitypes.typeid(c_type), IntTypeConverterMixin, TypeConverter):
+            _immutable_ = True
+            def __init__(self, space, default):
+                self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+        class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
+            _immutable_ = True
+            libffitype = libffi.types.pointer
+        for name in names:
+            _converters[name] = BasicConverter
+            _converters["const "+name+"&"] = ConstRefConverter
+
+    type_info = (
+        (rffi.LONG,       ("long", "long int")),
+        (rffi.LONGLONG,   ("long long", "long long int")),
+    )
+
+    for c_type, names in type_info:
+        class BasicConverter(ffitypes.typeid(c_type), IntTypeConverterMixin, TypeConverter):
+            _immutable_ = True
+            def __init__(self, space, default):
+                self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+        class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
+            _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
+        for name in names:
+            _converters[name] = BasicConverter
+            _converters["const "+name+"&"] = ConstRefConverter
+
+    # unsigned integer types (use strtoull in setting of default in __init__)
+    type_info = (
+        (rffi.USHORT,     ("unsigned short", "unsigned short int")),
+        (rffi.UINT,       ("unsigned", "unsigned int")),
+        (rffi.ULONG,      ("unsigned long", "unsigned long int")),
+        (rffi.ULONGLONG,  ("unsigned long long", "unsigned long long int")),
+    )
+
+    for c_type, names in type_info:
+        class BasicConverter(ffitypes.typeid(c_type), IntTypeConverterMixin, TypeConverter):
+            _immutable_ = True
+            def __init__(self, space, default):
+                self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+        class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
+            _immutable_ = True
+            libffitype = libffi.types.pointer
+        for name in names:
+            _converters[name] = BasicConverter
+            _converters["const "+name+"&"] = ConstRefConverter
+_build_basic_converters()
+
+# create the array and pointer converters; all real work is in the mixins
 def _build_array_converters():
     "NOT_RPYTHON"
     array_info = (
+        ('b', rffi.sizeof(rffi.UCHAR),  ("bool",)),    # is debatable, but works ...
         ('h', rffi.sizeof(rffi.SHORT),  ("short int", "short")),
         ('H', rffi.sizeof(rffi.USHORT), ("unsigned short int", "unsigned short")),
         ('i', rffi.sizeof(rffi.INT),    ("int",)),
@@ -817,16 +713,35 @@
         ('d', rffi.sizeof(rffi.DOUBLE), ("double",)),
     )
 
-    for info in array_info:
+    for tcode, tsize, names in array_info:
         class ArrayConverter(ArrayTypeConverterMixin, TypeConverter):
             _immutable_ = True
-            typecode = info[0]
-            typesize = info[1]
+            typecode = tcode
+            typesize = tsize
         class PtrConverter(PtrTypeConverterMixin, TypeConverter):
             _immutable_ = True
-            typecode = info[0]
-            typesize = info[1]
-        for name in info[2]:
+            typecode = tcode
+            typesize = tsize
+        for name in names:
             _a_converters[name+'[]'] = ArrayConverter
             _a_converters[name+'*']  = PtrConverter
 _build_array_converters()
+
+# add another set of aliased names
+def _add_aliased_converters():
+    "NOT_RPYTHON"
+    aliases = (
+        ("char",                            "unsigned char"),
+        ("const char*",                     "char*"),
+
+        ("std::basic_string<char>",         "string"),
+        ("const std::basic_string<char>&",  "const string&"),
+        ("std::basic_string<char>&",        "string&"),
+
+        ("PyObject*",                       "_object*"),
+    )
+ 
+    for c_type, alias in aliases:
+        _converters[alias] = _converters[c_type]
+_add_aliased_converters()
+
diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py
--- a/pypy/module/cppyy/executor.py
+++ b/pypy/module/cppyy/executor.py
@@ -6,9 +6,22 @@
 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._rawffi.array import W_Array, W_ArrayInstance
 
-from pypy.module.cppyy import helper, capi
+from pypy.module.cppyy import helper, capi, ffitypes
+
+# Executor objects are used to dispatch C++ methods. They are defined by their
+# return type only: arguments are converted by Converter objects, and Executors
+# only deal with arrays of memory that are either passed to a stub or libffi.
+# No argument checking or conversions are done.
+#
+# If a libffi function is not implemented, FastCallNotPossible is raised. If a
+# stub function is missing (e.g. if no reflection info is available for the
+# return type), an app-level TypeError is raised.
+#
+# Executor instances are created by get_executor(<return type name>), see
+# below. The name given should be qualified in case there is a specialised,
+# exact match for the qualified type.
 
 
 NULL = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
@@ -39,6 +52,14 @@
         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)))
+        if address == 0:
+            # TODO: fix this hack; fromaddress() will allocate memory if address
+            # is null and there seems to be no way around it (ll_buffer can not
+            # be touched directly)
+            nullarr = arr.fromaddress(space, address, 0)
+            assert isinstance(nullarr, W_ArrayInstance)
+            nullarr.free(space)
+            return nullarr
         return arr.fromaddress(space, address, sys.maxint)
 
 
@@ -55,175 +76,50 @@
         return space.w_None
 
 
-class BoolExecutor(FunctionExecutor):
+class NumericExecutorMixin(object):
+    _mixin_ = True
     _immutable_ = True
-    libffitype = libffi.types.schar
+
+    def _wrap_object(self, space, obj):
+        return space.wrap(obj)
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
-        result = capi.c_call_b(cppmethod, cppthis, num_args, args)
-        return space.wrap(result)
+        result = self.c_stubcall(cppmethod, cppthis, num_args, args)
+        return self._wrap_object(space, rffi.cast(self.c_type, result))
 
     def execute_libffi(self, space, libffifunc, argchain):
-        result = libffifunc.call(argchain, rffi.CHAR)
-        return space.wrap(bool(ord(result)))
+        result = libffifunc.call(argchain, self.c_type)
+        return self._wrap_object(space, result)
 
-class CharExecutor(FunctionExecutor):
+class NumericRefExecutorMixin(object):
+    _mixin_ = True
     _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 __init__(self, space, extra):
+        FunctionExecutor.__init__(self, space, extra)
+        self.do_assign = False
+        self.item = rffi.cast(self.c_type, 0)
 
-    def execute_libffi(self, space, libffifunc, argchain):
-        result = libffifunc.call(argchain, rffi.CHAR)
-        return space.wrap(result)
+    def set_item(self, space, w_item):
+        self.item = self._unwrap_object(space, w_item)
+        self.do_assign = True
 
-class ShortExecutor(FunctionExecutor):
-    _immutable_ = True
-    libffitype = libffi.types.sshort
+    def _wrap_object(self, space, obj):
+        return space.wrap(rffi.cast(self.c_type, obj))
 
-    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 _wrap_reference(self, space, rffiptr):
+        if self.do_assign:
+            rffiptr[0] = self.item
+        self.do_assign = False
+        return self._wrap_object(space, rffiptr[0])    # all paths, for rtyper
 
     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)
+        return self._wrap_reference(space, rffi.cast(self.c_ptrtype, 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)
+        result = libffifunc.call(argchain, self.c_ptrtype)
+        return self._wrap_reference(space, result)
 
 
 class CStringExecutor(FunctionExecutor):
@@ -236,35 +132,6 @@
         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
 
@@ -380,7 +247,7 @@
         pass
 
     compound = helper.compound(name)
-    clean_name = helper.clean_type(name)
+    clean_name = capi.c_resolve_name(helper.clean_type(name))
 
     #   1a) clean lookup
     try:
@@ -410,7 +277,7 @@
         elif compound == "**" or compound == "*&":
             return InstancePtrPtrExecutor(space, cppclass)
     elif capi.c_is_enum(clean_name):
-        return UnsignedIntExecutor(space, None)
+        return _executors['unsigned int'](space, None)
 
     # 4) additional special cases
     # ... none for now
@@ -421,46 +288,80 @@
 
 _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["const char*"]         = CStringExecutor
 
+# special cases
 _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["std::basic_string<char>"]         = StdStringExecutor
+_executors["const std::basic_string<char>&"]  = StdStringExecutor
+_executors["std::basic_string<char>&"]        = StdStringExecutor    # TODO: shouldn't copy
 
 _executors["PyObject*"]           = PyObjectExecutor
-_executors["_object*"]            = _executors["PyObject*"]
+
+# add basic (builtin) executors
+def _build_basic_executors():
+    "NOT_RPYTHON"
+    type_info = (
+        (bool,            capi.c_call_b,   ("bool",)),
+        (rffi.CHAR,       capi.c_call_c,   ("char", "unsigned char")),
+        (rffi.SHORT,      capi.c_call_h,   ("short", "short int", "unsigned short", "unsigned short int")),
+        (rffi.INT,        capi.c_call_i,   ("int",)),
+        (rffi.UINT,       capi.c_call_l,   ("unsigned", "unsigned int")),
+        (rffi.LONG,       capi.c_call_l,   ("long", "long int")),
+        (rffi.ULONG,      capi.c_call_l,   ("unsigned long", "unsigned long int")),
+        (rffi.LONGLONG,   capi.c_call_ll,  ("long long", "long long int")),
+        (rffi.ULONGLONG,  capi.c_call_ll,  ("unsigned long long", "unsigned long long int")),
+        (rffi.FLOAT,      capi.c_call_f,   ("float",)),
+        (rffi.DOUBLE,     capi.c_call_d,   ("double",)),
+    )
+
+    for c_type, stub, names in type_info:
+        class BasicExecutor(ffitypes.typeid(c_type), NumericExecutorMixin, FunctionExecutor):
+            _immutable_ = True
+            c_stubcall  = staticmethod(stub)
+        class BasicRefExecutor(ffitypes.typeid(c_type), NumericRefExecutorMixin, FunctionExecutor):
+            _immutable_ = True
+            libffitype = libffi.types.pointer
+        for name in names:
+            _executors[name]              = BasicExecutor
+            _executors[name+'&']          = BasicRefExecutor
+            _executors['const '+name+'&'] = BasicRefExecutor     # no copy needed for builtins
+_build_basic_executors()
+
+# create the pointer executors; all real work is in the PtrTypeExecutor, since
+# all pointer types are of the same size
+def _build_ptr_executors():
+    "NOT_RPYTHON"
+    ptr_info = (
+        ('b', ("bool",)),     # really unsigned char, but this works ...
+        ('h', ("short int", "short")),
+        ('H', ("unsigned short int", "unsigned short")),
+        ('i', ("int",)),
+        ('I', ("unsigned int", "unsigned")),
+        ('l', ("long int", "long")),
+        ('L', ("unsigned long int", "unsigned long")),
+        ('f', ("float",)),
+        ('d', ("double",)),
+    )
+
+    for tcode, names in ptr_info:
+        class PtrExecutor(PtrTypeExecutor):
+            _immutable_ = True
+            typecode = tcode
+        for name in names:
+            _executors[name+'*'] = PtrExecutor
+_build_ptr_executors()
+
+# add another set of aliased names
+def _add_aliased_executors():
+    "NOT_RPYTHON"
+    aliases = (
+        ("const char*",                     "char*"),
+        ("std::basic_string<char>",         "string"),
+        ("PyObject*",                       "_object*"),
+    )
+
+    for c_type, alias in aliases:
+        _executors[alias] = _executors[c_type]
+_add_aliased_executors()
diff --git a/pypy/module/cppyy/ffitypes.py b/pypy/module/cppyy/ffitypes.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/ffitypes.py
@@ -0,0 +1,176 @@
+from pypy.interpreter.error import OperationError
+
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib.rarithmetic import r_singlefloat
+from pypy.rlib import libffi, rfloat
+
+# Mixins to share between converter and executor classes (in converter.py and
+# executor.py, respectively). Basically these mixins allow grouping of the
+# sets of libffi, rffi, and different space unwrapping calls. To get the right
+# mixin, a non-RPython function typeid() is used.
+
+
+class BoolTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.uchar
+    c_type      = rffi.UCHAR
+    c_ptrtype   = rffi.UCHARP
+
+    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 _wrap_object(self, space, obj):
+        return space.wrap(bool(ord(rffi.cast(rffi.CHAR, obj))))
+
+class CharTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.schar
+    c_type      = rffi.CHAR
+    c_ptrtype   = rffi.CCHARP           # there's no such thing as rffi.CHARP
+
+    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
+
+class ShortTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.sshort
+    c_type      = rffi.SHORT
+    c_ptrtype   = rffi.SHORTP
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(rffi.SHORT, space.int_w(w_obj))
+
+class UShortTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.ushort
+    c_type      = rffi.USHORT
+    c_ptrtype   = rffi.USHORTP
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(self.c_type, space.int_w(w_obj))
+
+class IntTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.sint
+    c_type      = rffi.INT
+    c_ptrtype   = rffi.INTP
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(self.c_type, space.c_int_w(w_obj))
+
+class UIntTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.uint
+    c_type      = rffi.UINT
+    c_ptrtype   = rffi.UINTP
+
+    def _unwrap_object(self, space, w_obj):
+        return rffi.cast(self.c_type, space.uint_w(w_obj))
+
+class LongTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype = libffi.types.slong
+    c_type     =  rffi.LONG
+    c_ptrtype   = rffi.LONGP
+
+    def _unwrap_object(self, space, w_obj):
+        return space.int_w(w_obj)
+
+class ULongTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype = libffi.types.ulong
+    c_type     = rffi.ULONG
+    c_ptrtype  = rffi.ULONGP
+
+    def _unwrap_object(self, space, w_obj):
+        return space.uint_w(w_obj)
+
+class LongLongTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.sint64
+    c_type      = rffi.LONGLONG
+    c_ptrtype   = rffi.LONGLONGP
+
+    def _unwrap_object(self, space, w_obj):
+        return space.r_longlong_w(w_obj)
+
+class ULongLongTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype = libffi.types.uint64
+    c_type     = rffi.ULONGLONG
+    c_ptrtype  = rffi.ULONGLONGP
+
+    def _unwrap_object(self, space, w_obj):
+        return space.r_ulonglong_w(w_obj)
+
+class FloatTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.float
+    c_type      = rffi.FLOAT
+    c_ptrtype   = rffi.FLOATP
+    typecode    = 'f'
+
+    def _unwrap_object(self, space, w_obj):
+        return r_singlefloat(space.float_w(w_obj))
+
+    def _wrap_object(self, space, obj):
+        return space.wrap(float(obj))
+
+class DoubleTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.double
+    c_type      = rffi.DOUBLE
+    c_ptrtype   = rffi.DOUBLEP
+    typecode    = 'd'
+
+    def _unwrap_object(self, space, w_obj):
+        return space.float_w(w_obj)
+
+
+def typeid(c_type):
+    "NOT_RPYTHON"
+    if c_type == bool:            return BoolTypeMixin
+    if c_type == rffi.CHAR:       return CharTypeMixin
+    if c_type == rffi.SHORT:      return ShortTypeMixin
+    if c_type == rffi.USHORT:     return UShortTypeMixin
+    if c_type == rffi.INT:        return IntTypeMixin
+    if c_type == rffi.UINT:       return UIntTypeMixin
+    if c_type == rffi.LONG:       return LongTypeMixin
+    if c_type == rffi.ULONG:      return ULongTypeMixin
+    if c_type == rffi.LONGLONG:   return LongLongTypeMixin
+    if c_type == rffi.ULONGLONG:  return ULongLongTypeMixin
+    if c_type == rffi.FLOAT:      return FloatTypeMixin
+    if c_type == rffi.DOUBLE:     return DoubleTypeMixin
+
+    # should never get here
+    raise TypeError("unknown rffi type: %s" % c_type)
diff --git a/pypy/module/cppyy/helper.py b/pypy/module/cppyy/helper.py
--- a/pypy/module/cppyy/helper.py
+++ b/pypy/module/cppyy/helper.py
@@ -43,7 +43,7 @@
     if name.endswith("]"):                       # array type?
         idx = name.rfind("[")
         if 0 < idx:
-             name = name[:idx]
+            name = name[:idx]
     elif name.endswith(">"):                     # template type?
         idx = name.find("<")
         if 0 < idx:      # always true, but just so that the translater knows
@@ -90,10 +90,10 @@
             return nargs and "__sub__" or "__neg__"
 
         if op == "++":  # prefix v.s. postfix increment (not python)
-            return nargs and "__postinc__" or "__preinc__";
+            return nargs and "__postinc__" or "__preinc__"
 
         if op == "--":  # prefix v.s. postfix decrement (not python)
-            return nargs and "__postdec__" or "__predec__";
+            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
diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h
--- a/pypy/module/cppyy/include/capi.h
+++ b/pypy/module/cppyy/include/capi.h
@@ -11,9 +11,13 @@
     typedef cppyy_scope_t cppyy_type_t;
     typedef long cppyy_object_t;
     typedef long cppyy_method_t;
+    typedef long cppyy_index_t;
     typedef void* (*cppyy_methptrgetter_t)(cppyy_object_t);
 
     /* name to opaque C++ scope representation -------------------------------- */
+    int cppyy_num_scopes(cppyy_scope_t parent);
+    char* cppyy_scope_name(cppyy_scope_t parent, int iscope);
+
     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);
@@ -26,13 +30,13 @@
 
     /* 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);
+    unsigned char 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);
+    float  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);
@@ -41,7 +45,7 @@
     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);
+    cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_scope_t scope, cppyy_index_t idx);
 
     /* handling of function argument buffer ----------------------------------- */
     void*  cppyy_allocate_function_args(size_t nargs);
@@ -66,21 +70,24 @@
 
     /* 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);
+    cppyy_index_t cppyy_method_index_at(cppyy_scope_t scope, int imeth);
+    cppyy_index_t cppyy_method_index_from_name(cppyy_scope_t scope, const char* name);
 
-    int cppyy_method_index(cppyy_scope_t scope, const char* name);
+    char* cppyy_method_name(cppyy_scope_t scope, cppyy_index_t idx);
+    char* cppyy_method_result_type(cppyy_scope_t scope, cppyy_index_t idx);
+    int cppyy_method_num_args(cppyy_scope_t scope, cppyy_index_t idx);
+    int cppyy_method_req_args(cppyy_scope_t scope, cppyy_index_t idx);
+    char* cppyy_method_arg_type(cppyy_scope_t scope, cppyy_index_t idx, int arg_index);
+    char* cppyy_method_arg_default(cppyy_scope_t scope, cppyy_index_t idx, int arg_index);
+    char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx);
 
-    cppyy_method_t cppyy_get_method(cppyy_scope_t scope, int method_index);
+    cppyy_method_t cppyy_get_method(cppyy_scope_t scope, cppyy_index_t idx);
+    cppyy_index_t cppyy_get_global_operator(
+        cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op);
 
     /* method properties -----------------------------------------------------  */
-    int cppyy_is_constructor(cppyy_type_t type, int method_index);
-    int cppyy_is_staticmethod(cppyy_type_t type, int method_index);
+    int cppyy_is_constructor(cppyy_type_t type, cppyy_index_t idx);
+    int cppyy_is_staticmethod(cppyy_type_t type, cppyy_index_t idx);
 
     /* data member reflection information ------------------------------------  */
     int cppyy_num_datamembers(cppyy_scope_t scope);
@@ -95,9 +102,9 @@
     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);
+    void cppyy_free(void* ptr);
 
     cppyy_object_t cppyy_charp2stdstring(const char* str);
     cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr);
diff --git a/pypy/module/cppyy/include/cintcwrapper.h b/pypy/module/cppyy/include/cintcwrapper.h
--- a/pypy/module/cppyy/include/cintcwrapper.h
+++ b/pypy/module/cppyy/include/cintcwrapper.h
@@ -7,8 +7,14 @@
 extern "C" {
 #endif // ifdef __cplusplus
 
+    /* misc helpers */
     void* cppyy_load_dictionary(const char* lib_name);
 
+    /* pythonization helpers */
+    cppyy_object_t cppyy_ttree_Branch(
+        void* vtree, const char* branchname, const char* classname,
+        void* addobj, int bufsize, int splitlevel);
+
 #ifdef __cplusplus
 }
 #endif // ifdef __cplusplus
diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py
--- a/pypy/module/cppyy/interp_cppyy.py
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -59,7 +59,7 @@
             cppscope = W_CPPClass(space, final_name, opaque_handle)
         state.cppscope_cache[name] = cppscope
 
-        cppscope._find_methods()
+        cppscope._build_methods()
         cppscope._find_datamembers()
         return cppscope
 
@@ -91,6 +91,9 @@
 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)
+    # add back-end specific method pythonizations (doing this on the wrapped
+    # class allows simple aliasing of methods)
+    capi.pythonize(space, cppclass.name, w_pycppclass)
     state = space.fromcache(State)
     state.cppclass_registry[cppclass.handle] = w_pycppclass
 
@@ -109,7 +112,10 @@
 
 
 class CPPMethod(object):
-    """ A concrete function after overloading has been resolved """
+    """Dispatcher of methods. Checks the arguments, find the corresponding FFI
+    function if available, makes the call, and returns the wrapped result. It
+    also takes care of offset casting and recycling of known objects through
+    the memory_regulator."""
     _immutable_ = True
     
     def __init__(self, space, containing_scope, method_index, arg_defs, args_required):
@@ -255,6 +261,9 @@
 
 
 class CPPFunction(CPPMethod):
+    """Global (namespaced) function dispatcher. For now, the base class has
+    all the needed functionality, by allowing the C++ this pointer to be null
+    in the call. An optimization is expected there, however."""
     _immutable_ = True
 
     def __repr__(self):
@@ -262,6 +271,9 @@
 
 
 class CPPConstructor(CPPMethod):
+    """Method dispatcher that constructs new objects. In addition to the call,
+    it allocates memory for the newly constructed object and sets ownership
+    to Python."""
     _immutable_ = True
 
     def call(self, cppthis, args_w):
@@ -279,7 +291,27 @@
         return "CPPConstructor: %s" % self.signature()
 
 
+class CPPSetItem(CPPMethod):
+    """Method dispatcher specific to Python's __setitem__ mapped onto C++'s
+    operator[](int). The former function takes an extra argument to assign to
+    the return type of the latter."""
+    _immutable_ = True
+
+    def call(self, cppthis, args_w):
+        end = len(args_w)-1
+        if 0 <= end:
+            w_item = args_w[end]
+            args_w = args_w[:end]
+            if self.converters is None:
+                self._setup(cppthis)
+            self.executor.set_item(self.space, w_item) # TODO: what about threads?
+        CPPMethod.call(self, cppthis, args_w)
+
+
 class W_CPPOverload(Wrappable):
+    """Dispatcher that is actually available at the app-level: it is a
+    collection of (possibly) overloaded methods or functions. It calls these
+    in order and deals with error handling and reporting."""
     _immutable_ = True
 
     def __init__(self, space, containing_scope, functions):
@@ -412,29 +444,43 @@
         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
+        # Do not call "self._build_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.
+        # Idem as for 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 _build_methods(self):
+        assert len(self.methods) == 0
+        methods_temp = {}
+        for i in range(capi.c_num_methods(self)):
+            idx = capi.c_method_index_at(self, i)
+            pyname = helper.map_operator_name(
+                capi.c_method_name(self, idx),
+                capi.c_method_num_args(self, idx),
+                capi.c_method_result_type(self, idx))
+            cppmethod = self._make_cppfunction(pyname, idx)
+            methods_temp.setdefault(pyname, []).append(cppmethod)
+        # the following covers the case where the only kind of operator[](idx)
+        # returns are the ones that produce non-const references; these can be
+        # used for __getitem__ just as much as for __setitem__, though
+        if not "__getitem__" in methods_temp:
+            try:
+                for m in methods_temp["__setitem__"]:
+                    cppmethod = self._make_cppfunction("__getitem__", m.index)
+                    methods_temp.setdefault("__getitem__", []).append(cppmethod)
+            except KeyError:
+                pass          # just means there's no __setitem__ either
+
+        # create the overload methods from the method sets
+        for pyname, methods in methods_temp.iteritems():
+            overload = W_CPPOverload(self.space, self, methods[:])
+            self.methods[pyname] = overload
+
+    def full_name(self):
+        return capi.c_scoped_final_name(self.handle)
 
     def get_method_names(self):
         return self.space.newlist([self.space.wrap(name) for name in self.methods])
@@ -479,6 +525,9 @@
     def __eq__(self, other):
         return self.handle == other.handle
 
+    def __ne__(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
@@ -488,15 +537,15 @@
     _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)
+    def _make_cppfunction(self, pyname, index):
+        num_args = capi.c_method_num_args(self, index)
+        args_required = capi.c_method_req_args(self, 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_type = capi.c_method_arg_type(self, index, i)
+            arg_dflt = capi.c_method_arg_default(self, index, i)
             arg_defs.append((arg_type, arg_dflt))
-        return CPPFunction(self.space, self, method_index, arg_defs, args_required)
+        return CPPFunction(self.space, self, index, arg_defs, args_required)
 
     def _make_datamember(self, dm_name, dm_idx):
         type_name = capi.c_datamember_type(self, dm_idx)
@@ -516,10 +565,10 @@
 
     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:
+        meth_idx = capi.c_method_index_from_name(self, meth_name)
+        if meth_idx == -1:
             raise self.missing_attribute_error(meth_name)
-        cppfunction = self._make_cppfunction(meth_idx)
+        cppfunction = self._make_cppfunction(meth_name, meth_idx)
         overload = W_CPPOverload(self.space, self, [cppfunction])
         return overload
 
@@ -530,21 +579,38 @@
         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
 
+    def ns__dir__(self):
+        # Collect a list of everything (currently) available in the namespace.
+        # The backend can filter by returning empty strings. Special care is
+        # taken for functions, which need not be unique (overloading).
+        alldir = []
+        for i in range(capi.c_num_scopes(self)):
+            sname = capi.c_scope_name(self, i)
+            if sname: alldir.append(self.space.wrap(sname))
+        allmeth = {}
+        for i in range(capi.c_num_methods(self)):
+            idx = capi.c_method_index_at(self, i)
+            mname = capi.c_method_name(self, idx)
+            if mname: allmeth.setdefault(mname, 0)
+        for m in allmeth.keys():
+            alldir.append(self.space.wrap(m))
+        for i in range(capi.c_num_datamembers(self)):
+            dname = capi.c_datamember_name(self, i)
+            if dname: alldir.append(self.space.wrap(dname))
+        return self.space.newlist(alldir)
+        
+
 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),
+    __dir__ = interp2app(W_CPPNamespace.ns__dir__),
 )
 W_CPPNamespace.typedef.acceptable_as_base_class = False
 
@@ -553,21 +619,33 @@
     _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)
+    def __init__(self, space, name, opaque_handle):
+        W_CPPScope.__init__(self, space, name, opaque_handle)
+        self.default_constructor = None
+
+    def _make_cppfunction(self, pyname, index):
+        default_constructor = False
+        num_args = capi.c_method_num_args(self, index)
+        args_required = capi.c_method_req_args(self, 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_type = capi.c_method_arg_type(self, index, i)
+            arg_dflt = capi.c_method_arg_default(self, index, i)
             arg_defs.append((arg_type, arg_dflt))
-        if capi.c_is_constructor(self, method_index):
+        if capi.c_is_constructor(self, index):
             cls = CPPConstructor
-        elif capi.c_is_staticmethod(self, method_index):
+            if args_required == 0:
+                default_constructor = True
+        elif capi.c_is_staticmethod(self, index):
             cls = CPPFunction
+        elif pyname == "__setitem__":
+            cls = CPPSetItem
         else:
             cls = CPPMethod
-        return cls(self.space, self, method_index, arg_defs, args_required)
+        cppfunction = cls(self.space, self, index, arg_defs, args_required)
+        if default_constructor:
+            self.default_constructor = cppfunction
+        return cppfunction
 
     def _find_datamembers(self):
         num_datamembers = capi.c_num_datamembers(self)
@@ -581,6 +659,11 @@
             datamember = W_CPPDataMember(self.space, self, type_name, offset, is_static)
             self.datamembers[datamember_name] = datamember
 
+    def construct(self):
+        if self.default_constructor is not None:
+            return self.default_constructor.call(capi.C_NULL_OBJECT, [])
+        raise self.missing_attribute_error("default_constructor")
+
     def find_overload(self, name):
         raise self.missing_attribute_error(name)
 
@@ -698,7 +781,21 @@
 
     def instance__eq__(self, w_other):
         other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False)
-        iseq = self._rawobject == other._rawobject
+        # get here if no class-specific overloaded operator is available, try to
+        # find a global overload in gbl, in __gnu_cxx (for iterators), or in the
+        # scopes of the argument classes (TODO: implement that last)
+        for name in ["", "__gnu_cxx"]:
+            nss = scope_byname(self.space, name)
+            meth_idx = capi.c_get_global_operator(nss, self.cppclass, other.cppclass, "==")
+            if meth_idx != -1:
+                f = nss._make_cppfunction("operator==", meth_idx)
+                ol = W_CPPOverload(self.space, nss, [f])
+                # TODO: cache this operator
+                return ol.call(self, [self, w_other])
+        
+        # fallback: direct pointer comparison (the class comparison is needed since the
+        # first data member in a struct and the struct have the same address)
+        iseq = (self._rawobject == other._rawobject) and (self.cppclass == other.cppclass)
         return self.space.wrap(iseq)
 
     def instance__ne__(self, w_other):
@@ -765,10 +862,12 @@
         w_pycppclass = state.cppclass_registry[handle]
     except KeyError:
         final_name = capi.c_scoped_final_name(handle)
+        # the callback will cache the class by calling register_class
         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):
+    rawobject = rffi.cast(capi.C_OBJECT, rawobject)
     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)
@@ -778,12 +877,14 @@
     return w_cppinstance
 
 def wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+    rawobject = rffi.cast(capi.C_OBJECT, rawobject)
     obj = memory_regulator.retrieve(rawobject)
-    if obj and obj.cppclass == cppclass:
+    if obj is not None and obj.cppclass is 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):
+    rawobject = rffi.cast(capi.C_OBJECT, rawobject)
     if rawobject:
         actual = capi.c_actual_class(cppclass, rawobject)
         if actual != cppclass.handle:
@@ -796,11 +897,13 @@
 
 @unwrap_spec(cppinstance=W_CPPInstance)
 def addressof(space, cppinstance):
-     address = rffi.cast(rffi.LONG, cppinstance.get_rawobject())
-     return space.wrap(address)
+    """Takes a bound C++ instance, returns the raw address."""
+    address = rffi.cast(rffi.LONG, cppinstance.get_rawobject())
+    return space.wrap(address)
 
 @unwrap_spec(address=int, owns=bool)
 def bind_object(space, address, w_pycppclass, owns=False):
+    """Takes an address and a bound C++ class proxy, returns a bound instance."""
     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)
diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py
--- a/pypy/module/cppyy/pythonify.py
+++ b/pypy/module/cppyy/pythonify.py
@@ -1,6 +1,6 @@
 # NOT_RPYTHON
 import cppyy
-import types
+import types, sys
 
 
 # For now, keep namespaces and classes separate as namespaces are extensible
@@ -15,7 +15,8 @@
             raise AttributeError("%s object has no attribute '%s'" % (self, name))
 
 class CppyyNamespaceMeta(CppyyScopeMeta):
-    pass
+    def __dir__(cls):
+        return cls._cpp_proxy.__dir__()
 
 class CppyyClass(CppyyScopeMeta):
     pass
@@ -124,6 +125,8 @@
             setattr(pycppns, dm, pydm)
             setattr(metans, dm, pydm)
 
+        modname = pycppns.__name__.replace('::', '.')
+        sys.modules['cppyy.gbl.'+modname] = pycppns
     return pycppns
 
 def _drop_cycles(bases):
@@ -196,8 +199,10 @@
         if cppdm.is_static():
             setattr(metacpp, dm_name, pydm)
 
+    # the call to register will add back-end specific pythonizations and thus
+    # needs to run first, so that the generic pythonizations can use them
+    cppyy._register_class(pycppclass)
     _pythonize(pycppclass)
-    cppyy._register_class(pycppclass)
     return pycppclass
 
 def make_cpptemplatetype(scope, template_name):
@@ -251,7 +256,7 @@
         except AttributeError:
             pass
 
-    if not (pycppitem is None):   # pycppitem could be a bound C++ NULL, so check explicitly for Py_None
+    if pycppitem is not 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))
@@ -318,21 +323,15 @@
             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
+    # map begin()/end() protocol to iter protocol on STL(-like) classes, but
+    # not on vector, for which otherwise the user has to make sure that the
+    # global == and != for its iterators are reflected, which is a hassle ...
+    if not 'vector' in pyclass.__name__[:11] and \
+            (hasattr(pyclass, 'begin') and hasattr(pyclass, 'end')):
+        # TODO: check return type of begin() and end() for existence
         def __iter__(self):
             iter = self.begin()
-            while gbl.__gnu_cxx.__ne__(iter, self.end()):
+            while iter != self.end():
                 yield iter.__deref__()
                 iter.__preinc__()
             iter.destruct()
@@ -357,32 +356,35 @@
         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):
+    """Takes the name of a library containing reflection info, returns a handle
+    to the loaded library."""
     try:
         return _loaded_dictionaries[name]
     except KeyError:
-        dct = cppyy._load_dictionary(name)
-        _loaded_dictionaries[name] = dct
-        return dct
+        lib = cppyy._load_dictionary(name)
+        _loaded_dictionaries[name] = lib
+        return lib
     
 
 # 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
+gbl.__doc__ = "Global C++ namespace."
+sys.modules['cppyy.gbl'] = gbl
 
 # mostly for the benefit of the CINT backend, which treats std as special
 gbl.std = make_cppnamespace(None, "std", None, False)
+sys.modules['cppyy.gbl.std'] = gbl.std
 
 # user-defined pythonizations interface
 _pythonizations = {}
 def add_pythonization(class_name, callback):
+    """Takes a class name and a callback. The callback should take a single
+    argument, the class proxy, and is called the first time the named class
+    is bound."""
     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
--- a/pypy/module/cppyy/src/cintcwrapper.cxx
+++ b/pypy/module/cppyy/src/cintcwrapper.cxx
@@ -1,8 +1,6 @@
 #include "cppyy.h"
 #include "cintcwrapper.h"
 
-#include "Api.h"
-
 #include "TROOT.h"
 #include "TError.h"
 #include "TList.h"
@@ -16,12 +14,19 @@
 #include "TClass.h"
 #include "TClassEdit.h"
 #include "TClassRef.h"
+#include "TClassTable.h"
 #include "TDataMember.h"
 #include "TFunction.h"
 #include "TGlobal.h"
 #include "TMethod.h"
 #include "TMethodArg.h"
 
+// for pythonization
+#include "TTree.h"
+#include "TBranch.h"
+
+#include "Api.h"
+
 #include <assert.h>
 #include <string.h>
 #include <map>
@@ -30,9 +35,8 @@
 #include <utility>
 
 
-/*  CINT internals (some won't work on Windows) -------------------------- */
+/* ROOT/CINT internals --------------------------------------------------- */
 extern long G__store_struct_offset;
-extern "C" void* G__SetShlHandle(char*);
 extern "C" void G__LockCriticalSection();
 extern "C" void G__UnlockCriticalSection();
 
@@ -65,26 +69,15 @@
 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;
 
+typedef std::vector<G__MethodInfo> InterpretedFuncs_t;
+static InterpretedFuncs_t g_interpreted;
+
 
 /* initialization of the ROOT system (debatable ... ) --------------------- */
 namespace {
@@ -94,12 +87,12 @@
     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");
+        // 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) {
+        if (do_load) {
             // follow TRint to minimize differences with CINT
             ProcessLine("#include <iostream>", kTRUE);
             ProcessLine("#include <_string>",  kTRUE); // for std::string iostream.
@@ -129,10 +122,30 @@
 class ApplicationStarter {
 public:
     ApplicationStarter() {
+        // 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.
+ 
+        // an offset for the interpreted methods
+        g_interpreted.push_back(G__MethodInfo());
+
+        // actual application init, if necessary
         if (!gApplication) {
             int argc = 1;
             char* argv[1]; argv[0] = (char*)appname;
             gApplication = new TCppyyApplication(appname, &argc, argv, kTRUE);
+            if (!gProgName)                  // should have been set by TApplication
+                gSystem->SetProgname(appname);
+        }
+
+        // program name should've been set by TApplication; just in case ...
+        if (!gProgName) {
+            gSystem->SetProgname(appname);
         }
     }
 } _applicationStarter;
@@ -141,6 +154,13 @@
 
 
 /* local helpers ---------------------------------------------------------- */
+static inline const std::string resolve_typedef(const std::string& tname) {
+    G__TypeInfo ti(tname.c_str());
+    if (!ti.IsValid())
+        return tname;
+    return TClassEdit::ShortType(TClassEdit::CleanType(ti.TrueName(), 1).c_str(), 3);
+}
+
 static inline char* cppstring_to_cstring(const std::string& name) {
     char* name_char = (char*)malloc(name.size() + 1);
     strcpy(name_char, name.c_str());
@@ -154,17 +174,17 @@
 }
 
 static inline TClassRef type_from_handle(cppyy_type_t handle) {
+    assert((ClassRefs_t::size_type)handle < g_classrefs.size());
     return g_classrefs[(ClassRefs_t::size_type)handle];
 }
 
-static inline TFunction* type_get_method(cppyy_type_t handle, int method_index) {
+static inline TFunction* type_get_method(cppyy_type_t handle, cppyy_index_t idx) {
     TClassRef cr = type_from_handle(handle);
     if (cr.GetClass())
-        return (TFunction*)cr->GetListOfMethods()->At(method_index);
-    return &g_globalfuncs[method_index];
+        return (TFunction*)cr->GetListOfMethods()->At(idx);
+    return (TFunction*)idx;
 }
 
-
 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;
@@ -194,7 +214,6 @@
             libp->para[i].ref = (long)&libp->para[i].obj.i;
             libp->para[i].type = 'd';
             break;
-
         }
         }
     }
@@ -202,16 +221,58 @@
 
 
 /* name to opaque C++ scope representation -------------------------------- */
+int cppyy_num_scopes(cppyy_scope_t handle) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass()) {
+        /* not supported as CINT does not store classes hierarchically */
+        return 0;
+    }
+    return gClassTable->Classes();
+}
+
+char* cppyy_scope_name(cppyy_scope_t handle, int iscope) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass()) {
+        /* not supported as CINT does not store classes hierarchically */
+        assert(!"scope name lookup not supported on inner scopes");
+        return 0;
+    }
+    std::string name = gClassTable->At(iscope);
+    if (name.find("::") == std::string::npos)
+        return cppstring_to_cstring(name);
+    return cppstring_to_cstring("");
+}
+
 char* cppyy_resolve_name(const char* cppitem_name) {
-    if (strcmp(cppitem_name, "") == 0)
+    std::string tname = cppitem_name;
+
+    // global namespace?
+    if (tname.empty())
         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);
+
+    // special care needed for builtin arrays
+    std::string::size_type pos = tname.rfind("[");
+    G__TypeInfo ti(tname.substr(0, pos).c_str());
+
+    // if invalid (most likely unknown), simply return old name
+    if (!ti.IsValid())
+        return cppstring_to_cstring(cppitem_name);
+
+    // special case treatment of enum types as unsigned int (CINTism)
+    if (ti.Property() & G__BIT_ISENUM)
+        return cppstring_to_cstring("unsigned int");
+
+    // actual typedef resolution; add back array declartion portion, if needed
+    std::string rt = ti.TrueName();
+
+    // builtin STL types have fake typedefs :/
+    G__TypeInfo ti_test(rt.c_str());
+    if (!ti_test.IsValid())
+        return cppstring_to_cstring(cppitem_name);
+
+    if (pos != std::string::npos)
+        rt += tname.substr(pos, std::string::npos);
+    return cppstring_to_cstring(rt);
 }
 
 cppyy_scope_t cppyy_get_scope(const char* scope_name) {
@@ -261,6 +322,7 @@
     return klass;
 }
 
+
 /* memory management ------------------------------------------------------ */
 cppyy_object_t cppyy_allocate(cppyy_type_t handle) {
     TClassRef cr = type_from_handle(handle);
@@ -281,11 +343,25 @@
 static inline G__value cppyy_call_T(cppyy_method_t method,
         cppyy_object_t self, int nargs, void* args) {
 
-    G__InterfaceMethod meth = (G__InterfaceMethod)method;
     G__param* libp = (G__param*)((char*)args - offsetof(G__param, para));
     assert(libp->paran == nargs);
     fixup_args(libp);
 
+    if ((InterpretedFuncs_t::size_type)method < g_interpreted.size()) {
+    // the idea here is that all these low values are invalid memory addresses,
+    // allowing the reuse of method to index the stored bytecodes
+        G__CallFunc callf;
+        callf.SetFunc(g_interpreted[(size_t)method]);
+        G__param p;      // G__param has fixed size; libp is sized to nargs
+        for (int i =0; i<nargs; ++i)
+            p.para[i] = libp->para[i];
+        p.paran = nargs;
+        callf.SetArgs(p);     // will copy p yet again
+        return callf.Execute((void*)self);
+    }
+
+    G__InterfaceMethod meth = (G__InterfaceMethod)method;
+
     G__value result;
     G__setnull(&result);
 
@@ -294,13 +370,13 @@
 
     long index = (long)&method;
     G__CurrentCall(G__SETMEMFUNCENV, 0, &index);
-    
+
     // TODO: access to store_struct_offset won't work on Windows
     long store_struct_offset = G__store_struct_offset;
     if (self)
         G__store_struct_offset = (long)self;
 
-    meth(&result, 0, libp, 0);
+    meth(&result, (char*)0, libp, 0);
     if (self)
         G__store_struct_offset = store_struct_offset;
 
@@ -318,9 +394,9 @@
     cppyy_call_T(method, self, nargs, args);
 }
 
-int cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
     G__value result = cppyy_call_T(method, self, nargs, args);
-    return (bool)G__int(result);
+    return (unsigned char)(bool)G__int(result);
 }
 
 char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
@@ -348,9 +424,9 @@
     return G__Longlong(result);
 }
 
-double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
     G__value result = cppyy_call_T(method, self, nargs, args);
-    return G__double(result);
+    return (float)G__double(result);
 }
 
 double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
@@ -387,7 +463,7 @@
     return G__int(result);
 }
 
-cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /*handle*/, int /*method_index*/) {
+cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /*handle*/, cppyy_index_t /*idx*/) {
     return (cppyy_methptrgetter_t)NULL;
 }
 
@@ -516,22 +592,15 @@
     if (cr.GetClass() && cr->GetListOfMethods())
         return cr->GetListOfMethods()->GetSize();
     else if (strcmp(cr.GetClassName(), "") == 0) {
-    // NOTE: the updated list of global funcs grows with 5 "G__ateval"'s just
-    // because it is being updated => infinite loop! Apply offset to correct ...
-        static int ateval_offset = 0;
-        TCollection* funcs = gROOT->GetListOfGlobalFunctions(kTRUE);
-        ateval_offset += 5;
-	if (g_globalfuncs.size() <= (GlobalFuncs_t::size_type)funcs->GetSize() - ateval_offset) {
-            g_globalfuncs.clear();
+        if (g_globalfuncs.empty()) {
+            TCollection* funcs = gROOT->GetListOfGlobalFunctions(kTRUE);
 	    g_globalfuncs.reserve(funcs->GetSize());
 
             TIter ifunc(funcs);
 
             TFunction* func = 0;
             while ((func = (TFunction*)ifunc.Next())) {
-                if (strcmp(func->GetName(), "G__ateval") == 0)
-                    ateval_offset += 1;
-                else
+                if (strcmp(func->GetName(), "G__ateval") != 0)
                     g_globalfuncs.push_back(*func);
             }
         }
@@ -540,47 +609,75 @@
     return 0;
 }
 
-char* cppyy_method_name(cppyy_scope_t handle, int method_index) {
-    TFunction* f = type_get_method(handle, method_index);
+cppyy_index_t cppyy_method_index_at(cppyy_scope_t handle, int imeth) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass())
+        return (cppyy_index_t)imeth;
+    return (cppyy_index_t)&g_globalfuncs[imeth];
+}
+
+cppyy_index_t cppyy_method_index_from_name(cppyy_scope_t handle, const char* name) {
+    TClassRef cr = type_from_handle(handle);
+    if (cr.GetClass()) {
+        gInterpreter->UpdateListOfMethods(cr.GetClass());
+        int imeth = 0;
+        TFunction* func;
+        TIter next(cr->GetListOfMethods());
+        while ((func = (TFunction*)next())) {
+            if (strcmp(name, func->GetName()) == 0) {
+                if (func->Property() & G__BIT_ISPUBLIC)
+                    return (cppyy_index_t)imeth;
+                return (cppyy_index_t)-1;
+            }
+            ++imeth;
+        }
+    }
+    TFunction* func = gROOT->GetGlobalFunction(name, NULL, kTRUE);
+    if (!func)
+        return (cppyy_index_t)-1;  // (void*)-1 is in kernel space, so invalid
+    int idx = g_globalfuncs.size();
+    g_globalfuncs.push_back(*func);
+    return (cppyy_index_t)func;
+}
+
+
+char* cppyy_method_name(cppyy_scope_t handle, cppyy_index_t idx) {
+    TFunction* f = type_get_method(handle, idx);
     return cppstring_to_cstring(f->GetName());
 }
 
-char* cppyy_method_result_type(cppyy_scope_t handle, int method_index) {
-    TFunction* f = 0;
+char* cppyy_method_result_type(cppyy_scope_t handle, cppyy_index_t idx) {
     TClassRef cr = type_from_handle(handle);
-    if (cr.GetClass()) {
-        if (cppyy_is_constructor(handle, method_index))
-            return cppstring_to_cstring("constructor");
-        f = (TFunction*)cr->GetListOfMethods()->At(method_index);
-    } else
-        f = &g_globalfuncs[method_index];
+    if (cr.GetClass() && cppyy_is_constructor(handle, idx))
+        return cppstring_to_cstring("constructor");
+    TFunction* f = type_get_method(handle, idx);
     return type_cppstring_to_cstring(f->GetReturnTypeName());
 }
 
-int cppyy_method_num_args(cppyy_scope_t handle, int method_index) {
-    TFunction* f = type_get_method(handle, method_index);
+int cppyy_method_num_args(cppyy_scope_t handle, cppyy_index_t idx) {
+    TFunction* f = type_get_method(handle, idx);
     return f->GetNargs();
 }
 
-int cppyy_method_req_args(cppyy_scope_t handle, int method_index) {
-    TFunction* f = type_get_method(handle, method_index);
+int cppyy_method_req_args(cppyy_scope_t handle, cppyy_index_t idx) {
+    TFunction* f = type_get_method(handle, idx);
     return f->GetNargs() - f->GetNargsOpt();
 }
 
-char* cppyy_method_arg_type(cppyy_scope_t handle, int method_index, int arg_index) {
-    TFunction* f = type_get_method(handle, method_index);
+char* cppyy_method_arg_type(cppyy_scope_t handle, cppyy_index_t idx, int arg_index) {
+    TFunction* f = type_get_method(handle, idx);
     TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At(arg_index);
     return type_cppstring_to_cstring(arg->GetFullTypeName());
 }
 
-char* cppyy_method_arg_default(cppyy_scope_t, int, int) {
+char* cppyy_method_arg_default(cppyy_scope_t /*handle*/, cppyy_index_t /*idx*/, int /*arg_index*/) {
     /* unused: libffi does not work with CINT back-end */
     return cppstring_to_cstring("");
 }
 
-char* cppyy_method_signature(cppyy_scope_t handle, int method_index) {
-    TFunction* f = type_get_method(handle, method_index);
+char* cppyy_method_signature(cppyy_scope_t handle, cppyy_index_t idx) {
     TClassRef cr = type_from_handle(handle);
+    TFunction* f = type_get_method(handle, idx);
     std::ostringstream sig;
     if (cr.GetClass() && cr->GetClassInfo()
         && strcmp(f->GetName(), ((G__ClassInfo*)cr->GetClassInfo())->Name()) != 0)
@@ -596,46 +693,71 @@
     return cppstring_to_cstring(sig.str());
 }
 
-int cppyy_method_index(cppyy_scope_t handle, const char* name) {
+
+cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t idx) {
     TClassRef cr = type_from_handle(handle);
-    if (cr.GetClass()) {
-        gInterpreter->UpdateListOfMethods(cr.GetClass());
-        int imeth = 0;
-        TFunction* func;
-        TIter next(cr->GetListOfMethods());
-        while ((func = (TFunction*)next())) {
-            if (strcmp(name, func->GetName()) == 0) {
-                if (func->Property() & G__BIT_ISPUBLIC)
-                    return imeth;
-                return -1;
+    TFunction* f = type_get_method(handle, idx);
+    if (cr && cr.GetClass() && !cr->IsLoaded()) {
+        G__ClassInfo* gcl = (G__ClassInfo*)cr->GetClassInfo();
+        if (gcl) {
+            long offset;
+            std::ostringstream sig;
+            int nArgs = f->GetNargs();
+            for (int iarg = 0; iarg < nArgs; ++iarg) {
+                sig << ((TMethodArg*)f->GetListOfMethodArgs()->At(iarg))->GetFullTypeName();
+                if (iarg != nArgs-1) sig << ", ";
             }
-            ++imeth;
+            G__MethodInfo gmi = gcl->GetMethod(
+                f->GetName(), sig.str().c_str(), &offset, G__ClassInfo::ExactMatch);
+            cppyy_method_t method = (cppyy_method_t)g_interpreted.size();
+            g_interpreted.push_back(gmi);
+            return method;
         }
     }
-    TFunction* func = gROOT->GetGlobalFunction(name, NULL, kTRUE);
-    if (!func)
-        return -1;
-    int idx = g_globalfuncs.size();
-    g_globalfuncs.push_back(*func);
-    return idx;
+    cppyy_method_t method = (cppyy_method_t)f->InterfaceMethod();
+    return method;
 }
 
-cppyy_method_t cppyy_get_method(cppyy_scope_t handle, int method_index) {
-    TFunction* f = type_get_method(handle, method_index);
-    return (cppyy_method_t)f->InterfaceMethod();
+cppyy_index_t cppyy_get_global_operator(cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op) {
+    TClassRef lccr = type_from_handle(lc);
+    TClassRef rccr = type_from_handle(rc);
+
+    if (!lccr.GetClass() || !rccr.GetClass() || scope != GLOBAL_HANDLE)
+        return (cppyy_index_t)-1;  // (void*)-1 is in kernel space, so invalid as a method handle
+
+    std::string lcname = lccr->GetName();
+    std::string rcname = rccr->GetName();
+
+    std::string opname = "operator";
+    opname += op;
+
+    for (int idx = 0; idx < (int)g_globalfuncs.size(); ++idx) {
+        TFunction* func = &g_globalfuncs[idx];
+        if (func->GetListOfMethodArgs()->GetSize() != 2)
+            continue;
+
+        if (func->GetName() == opname) {
+            if (lcname == resolve_typedef(((TMethodArg*)func->GetListOfMethodArgs()->At(0))->GetTypeName()) &&
+                rcname == resolve_typedef(((TMethodArg*)func->GetListOfMethodArgs()->At(1))->GetTypeName())) {
+                return (cppyy_index_t)func;
+            }
+        }
+    }
+
+    return (cppyy_index_t)-1;
 }
 
 
 /* method properties -----------------------------------------------------  */
-int cppyy_is_constructor(cppyy_type_t handle, int method_index) {
+int cppyy_is_constructor(cppyy_type_t handle, cppyy_index_t idx) {
     TClassRef cr = type_from_handle(handle);
-    TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index);
+    TMethod* m = (TMethod*)cr->GetListOfMethods()->At(idx);
     return strcmp(m->GetName(), ((G__ClassInfo*)cr->GetClassInfo())->Name()) == 0;
 }
 
-int cppyy_is_staticmethod(cppyy_type_t handle, int method_index) {
+int cppyy_is_staticmethod(cppyy_type_t handle, cppyy_index_t idx) {
     TClassRef cr = type_from_handle(handle);
-    TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index);
+    TMethod* m = (TMethod*)cr->GetListOfMethods()->At(idx);
     return m->Property() & G__BIT_ISSTATIC;
 }
 
@@ -776,16 +898,27 @@
     return (cppyy_object_t)new std::string(*(std::string*)ptr);
 }
 
+void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str) {
+   *((std::string*)ptr) = str;
+}
+
 void cppyy_free_stdstring(cppyy_object_t ptr) {
     delete (std::string*)ptr;
 }
 
-void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str) {
-   *((std::string*)ptr) = str;
-}
 
 void* cppyy_load_dictionary(const char* lib_name) {
     if (0 <= gSystem->Load(lib_name))
         return (void*)1;
     return (void*)0;
 }
+
+
+/* pythonization helpers -------------------------------------------------- */
+cppyy_object_t cppyy_ttree_Branch(void* vtree, const char* branchname, const char* classname,
+        void* addobj, int bufsize, int splitlevel) {
+    // this little song-and-dance is to by-pass the handwritten Branch methods
+    TBranch* b = ((TTree*)vtree)->Bronch(branchname, classname, (void*)&addobj, bufsize, splitlevel);
+    if (b) b->SetObject(addobj);
+    return (cppyy_object_t)b;
+}
diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx
--- a/pypy/module/cppyy/src/reflexcwrapper.cxx
+++ b/pypy/module/cppyy/src/reflexcwrapper.cxx
@@ -53,6 +53,17 @@
 
 
 /* name to opaque C++ scope representation -------------------------------- */
+int cppyy_num_scopes(cppyy_scope_t handle) {
+    Reflex::Scope s = scope_from_handle(handle);
+    return s.SubScopeSize();
+}
+
+char* cppyy_scope_name(cppyy_scope_t handle, int iscope) {
+    Reflex::Scope s = scope_from_handle(handle);
+    std::string name = s.SubScopeAt(iscope).Name(Reflex::F);
+    return cppstring_to_cstring(name);
+}
+
 char* cppyy_resolve_name(const char* cppitem_name) {
     Reflex::Scope s = Reflex::Scope::ByName(cppitem_name);
     if (s.IsEnum())
@@ -122,8 +133,8 @@
     return result;
 }
 
-int cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
-    return (int)cppyy_call_T<bool>(method, self, nargs, args);
+unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    return (unsigned char)cppyy_call_T<bool>(method, self, nargs, args);
 }
 
 char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
@@ -146,7 +157,7 @@
     return cppyy_call_T<long long>(method, self, nargs, args);
 }
 
-double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
     return cppyy_call_T<float>(method, self, nargs, args);
 }
 
@@ -188,7 +199,7 @@
     return 0;
 }
 
-cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t handle, int method_index) {
+cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t handle, cppyy_index_t method_index) {
     Reflex::Scope s = scope_from_handle(handle);
     Reflex::Member m = s.FunctionMemberAt(method_index);
     return get_methptr_getter(m);
@@ -271,6 +282,13 @@
 
 int cppyy_num_bases(cppyy_type_t handle) {
     Reflex::Type t = type_from_handle(handle);
+    std::string name = t.Name(Reflex::FINAL|Reflex::SCOPED);
+    if (5 < name.size() && name.substr(0, 5) == "std::") {
+        // special case: STL base classes are usually unnecessary,
+        // so either build all (i.e. if available) or none
+        for (int i=0; i < (int)t.BaseSize(); ++i)
+            if (!t.BaseAt(i)) return 0;
+    }
     return t.BaseSize();
 }
 
@@ -332,7 +350,28 @@
     return s.FunctionMemberSize();
 }
 
-char* cppyy_method_name(cppyy_scope_t handle, int method_index) {
+cppyy_index_t cppyy_method_index_at(cppyy_scope_t scope, int imeth) {
+    return (cppyy_index_t)imeth;
+}
+
+cppyy_index_t cppyy_method_index_from_name(cppyy_scope_t handle, const char* name) {
+    Reflex::Scope s = scope_from_handle(handle);
+    // the following appears dumb, but the internal storage for Reflex is an
+    // unsorted std::vector anyway, so there's no gain to be had in using the
+    // Scope::FunctionMemberByName() function
+    int num_meth = s.FunctionMemberSize();
+    for (int imeth = 0; imeth < num_meth; ++imeth) {
+        Reflex::Member m = s.FunctionMemberAt(imeth);
+        if (m.Name() == name) {
+            if (m.IsPublic())
+               return (cppyy_index_t)imeth;
+            return (cppyy_index_t)-1;
+        }
+    }
+    return (cppyy_index_t)-1;
+}
+
+char* cppyy_method_name(cppyy_scope_t handle, cppyy_index_t method_index) {
     Reflex::Scope s = scope_from_handle(handle);
     Reflex::Member m = s.FunctionMemberAt(method_index);
     std::string name;
@@ -343,7 +382,7 @@
     return cppstring_to_cstring(name);
 }
 
-char* cppyy_method_result_type(cppyy_scope_t handle, int method_index) {
+char* cppyy_method_result_type(cppyy_scope_t handle, cppyy_index_t method_index) {
     Reflex::Scope s = scope_from_handle(handle);
     Reflex::Member m = s.FunctionMemberAt(method_index);
     if (m.IsConstructor())
@@ -353,19 +392,19 @@
     return cppstring_to_cstring(name);
 }
 
-int cppyy_method_num_args(cppyy_scope_t handle, int method_index) {
+int cppyy_method_num_args(cppyy_scope_t handle, cppyy_index_t method_index) {
     Reflex::Scope s = scope_from_handle(handle);
     Reflex::Member m = s.FunctionMemberAt(method_index);
     return m.FunctionParameterSize();
 }
 
-int cppyy_method_req_args(cppyy_scope_t handle, int method_index) {
+int cppyy_method_req_args(cppyy_scope_t handle, cppyy_index_t method_index) {
     Reflex::Scope s = scope_from_handle(handle);
     Reflex::Member m = s.FunctionMemberAt(method_index);
     return m.FunctionParameterSize(true);
 }
 
-char* cppyy_method_arg_type(cppyy_scope_t handle, int method_index, int arg_index) {
+char* cppyy_method_arg_type(cppyy_scope_t handle, cppyy_index_t method_index, int arg_index) {
     Reflex::Scope s = scope_from_handle(handle);
     Reflex::Member m = s.FunctionMemberAt(method_index);
     Reflex::Type at = m.TypeOf().FunctionParameterAt(arg_index);
@@ -373,14 +412,14 @@
     return cppstring_to_cstring(name);
 }
 
-char* cppyy_method_arg_default(cppyy_scope_t handle, int method_index, int arg_index) {
+char* cppyy_method_arg_default(cppyy_scope_t handle, cppyy_index_t method_index, int arg_index) {
     Reflex::Scope s = scope_from_handle(handle);
     Reflex::Member m = s.FunctionMemberAt(method_index);
     std::string dflt = m.FunctionParameterDefaultAt(arg_index);
     return cppstring_to_cstring(dflt);
 }
 
-char* cppyy_method_signature(cppyy_scope_t handle, int method_index) {
+char* cppyy_method_signature(cppyy_scope_t handle, cppyy_index_t method_index) {
     Reflex::Scope s = scope_from_handle(handle);
     Reflex::Member m = s.FunctionMemberAt(method_index);
     Reflex::Type mt = m.TypeOf();
@@ -398,39 +437,53 @@
     return cppstring_to_cstring(sig.str());
 }
 
-int cppyy_method_index(cppyy_scope_t handle, const char* name) {
-    Reflex::Scope s = scope_from_handle(handle);
-    // the following appears dumb, but the internal storage for Reflex is an
-    // unsorted std::vector anyway, so there's no gain to be had in using the
-    // Scope::FunctionMemberByName() function
-    int num_meth = s.FunctionMemberSize();
-    for (int imeth = 0; imeth < num_meth; ++imeth) {
-        Reflex::Member m = s.FunctionMemberAt(imeth);
-        if (m.Name() == name) {
-            if (m.IsPublic())
-                return imeth;
-            return -1;
-        }
-    }
-    return -1;
-}
-
-cppyy_method_t cppyy_get_method(cppyy_scope_t handle, int method_index) {
+cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t method_index) {
     Reflex::Scope s = scope_from_handle(handle);
     Reflex::Member m = s.FunctionMemberAt(method_index);
     assert(m.IsFunctionMember());
     return (cppyy_method_t)m.Stubfunction();
 }
 
+cppyy_method_t cppyy_get_global_operator(cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op) {
+    Reflex::Type lct = type_from_handle(lc);
+    Reflex::Type rct = type_from_handle(rc);
+    Reflex::Scope nss = scope_from_handle(scope);
+
+    if (!lct || !rct || !nss) 
+        return (cppyy_index_t)-1;  // (void*)-1 is in kernel space, so invalid as a method handle
+
+    std::string lcname = lct.Name(Reflex::SCOPED|Reflex::FINAL);
+    std::string rcname = rct.Name(Reflex::SCOPED|Reflex::FINAL);
+
+    std::string opname = "operator";
+    opname += op;
+
+    for (int idx = 0; idx < (int)nss.FunctionMemberSize(); ++idx) {
+        Reflex::Member m = nss.FunctionMemberAt(idx);
+        if (m.FunctionParameterSize() != 2)
+            continue;
+
+        if (m.Name() == opname) {
+            Reflex::Type mt = m.TypeOf();
+            if (lcname == mt.FunctionParameterAt(0).Name(Reflex::SCOPED|Reflex::FINAL) &&
+                rcname == mt.FunctionParameterAt(1).Name(Reflex::SCOPED|Reflex::FINAL)) {
+                return (cppyy_index_t)idx;
+            }
+        }
+    }
+
+    return (cppyy_index_t)-1;  
+}
+
 
 /* method properties -----------------------------------------------------  */
-int cppyy_is_constructor(cppyy_type_t handle, int method_index) {
+int cppyy_is_constructor(cppyy_type_t handle, cppyy_index_t method_index) {
     Reflex::Scope s = scope_from_handle(handle);
     Reflex::Member m = s.FunctionMemberAt(method_index);
     return m.IsConstructor();
 }
 
-int cppyy_is_staticmethod(cppyy_type_t handle, int method_index) {
+int cppyy_is_staticmethod(cppyy_type_t handle, cppyy_index_t method_index) {
     Reflex::Scope s = scope_from_handle(handle);
     Reflex::Member m = s.FunctionMemberAt(method_index);
     return m.IsStatic();
diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile
--- a/pypy/module/cppyy/test/Makefile
+++ b/pypy/module/cppyy/test/Makefile
@@ -1,6 +1,6 @@
 dicts = example01Dict.so datatypesDict.so advancedcppDict.so advancedcpp2Dict.so \
 overloadsDict.so stltypesDict.so operatorsDict.so fragileDict.so crossingDict.so \
-std_streamsDict.so
+std_streamsDict.so iotypesDict.so
 all : $(dicts)
 
 ROOTSYS := ${ROOTSYS}
diff --git a/pypy/module/cppyy/test/advancedcpp.cxx b/pypy/module/cppyy/test/advancedcpp.cxx
--- a/pypy/module/cppyy/test/advancedcpp.cxx
+++ b/pypy/module/cppyy/test/advancedcpp.cxx
@@ -2,11 +2,20 @@
 
 
 // for testing of default arguments
-defaulter::defaulter(int a, int b, int c ) {
-   m_a = a;
-   m_b = b;
-   m_c = c;
+#define IMPLEMENT_DEFAULTER_CLASS(type, tname)                               \
+tname##_defaulter::tname##_defaulter(type a, type b, type c) {               \
+   m_a = a; m_b = b; m_c = c;                                                \
 }
+IMPLEMENT_DEFAULTER_CLASS(short, short)
+IMPLEMENT_DEFAULTER_CLASS(unsigned short, ushort)
+IMPLEMENT_DEFAULTER_CLASS(int, int)
+IMPLEMENT_DEFAULTER_CLASS(unsigned, uint)
+IMPLEMENT_DEFAULTER_CLASS(long, long)
+IMPLEMENT_DEFAULTER_CLASS(unsigned long, ulong)
+IMPLEMENT_DEFAULTER_CLASS(long long, llong)
+IMPLEMENT_DEFAULTER_CLASS(unsigned long long, ullong)
+IMPLEMENT_DEFAULTER_CLASS(float, float)
+IMPLEMENT_DEFAULTER_CLASS(double, double)
 
 
 // for esoteric inheritance testing
diff --git a/pypy/module/cppyy/test/advancedcpp.h b/pypy/module/cppyy/test/advancedcpp.h
--- a/pypy/module/cppyy/test/advancedcpp.h
+++ b/pypy/module/cppyy/test/advancedcpp.h
@@ -2,13 +2,24 @@
 
 
 //===========================================================================
-class defaulter {                 // for testing of default arguments
-public:
-    defaulter(int a = 11, int b = 22, int c = 33 );
-
-public:
-    int m_a, m_b, m_c;
+#define DECLARE_DEFAULTER_CLASS(type, tname)                                \
+class tname##_defaulter {                                                   \
+public:                                                                     \
+    tname##_defaulter(type a = 11, type b = 22, type c = 33);               \
+                                                                            \
+public:                                                                     \
+    type m_a, m_b, m_c;                                                     \
 };
+DECLARE_DEFAULTER_CLASS(short, short)   // for testing of default arguments
+DECLARE_DEFAULTER_CLASS(unsigned short, ushort)
+DECLARE_DEFAULTER_CLASS(int, int)
+DECLARE_DEFAULTER_CLASS(unsigned, uint)
+DECLARE_DEFAULTER_CLASS(long, long)
+DECLARE_DEFAULTER_CLASS(unsigned long, ulong)
+DECLARE_DEFAULTER_CLASS(long long, llong)
+DECLARE_DEFAULTER_CLASS(unsigned long long, ullong)
+DECLARE_DEFAULTER_CLASS(float, float)
+DECLARE_DEFAULTER_CLASS(double, double)
 
 
 //===========================================================================
@@ -303,6 +314,16 @@
     long gime_address_ptr_ref(void*& obj) {
         return (long)obj;
     }
+
+    static long set_address_ptr_ptr(void** obj) {
+        (*(long**)obj) = (long*)0x4321;
+        return 42;
+    }
+
+    static long set_address_ptr_ref(void*& obj) {
+        obj = (void*)0x1234;
+        return 21;
+    }
 };
 
 
diff --git a/pypy/module/cppyy/test/advancedcpp.xml b/pypy/module/cppyy/test/advancedcpp.xml
--- a/pypy/module/cppyy/test/advancedcpp.xml
+++ b/pypy/module/cppyy/test/advancedcpp.xml
@@ -1,6 +1,6 @@
 <lcgdict>
 
-  <class name="defaulter" />
+  <class pattern="*_defaulter" />
 
   <class name="base_class" />
   <class name="derived_class" />
diff --git a/pypy/module/cppyy/test/advancedcpp_LinkDef.h b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
--- a/pypy/module/cppyy/test/advancedcpp_LinkDef.h
+++ b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
@@ -4,7 +4,16 @@
 #pragma link off all classes;
 #pragma link off all functions;
 
-#pragma link C++ class defaulter;
+#pragma link C++ class short_defaulter;
+#pragma link C++ class ushort_defaulter;
+#pragma link C++ class int_defaulter;
+#pragma link C++ class uint_defaulter;
+#pragma link C++ class long_defaulter;
+#pragma link C++ class ulong_defaulter;
+#pragma link C++ class llong_defaulter;
+#pragma link C++ class ullong_defaulter;
+#pragma link C++ class float_defaulter;
+#pragma link C++ class double_defaulter;
 
 #pragma link C++ class base_class;
 #pragma link C++ class derived_class;
diff --git a/pypy/module/cppyy/test/datatypes.cxx b/pypy/module/cppyy/test/datatypes.cxx
--- a/pypy/module/cppyy/test/datatypes.cxx
+++ b/pypy/module/cppyy/test/datatypes.cxx
@@ -1,7 +1,5 @@
 #include "datatypes.h"
 
-#include <iostream>
-
 
 //===========================================================================
 cppyy_test_data::cppyy_test_data() : m_owns_arrays(false)
@@ -21,6 +19,7 @@
     m_double = -77.;
     m_enum   = kNothing;
 
+    m_bool_array2   = new bool[N];
     m_short_array2  = new short[N];
     m_ushort_array2 = new unsigned short[N];
     m_int_array2    = new int[N];
@@ -32,6 +31,8 @@
     m_double_array2 = new double[N];
 
     for (int i = 0; i < N; ++i) {
+        m_bool_array[i]    =  bool(i%2);
+        m_bool_array2[i]   =  bool((i+1)%2);
         m_short_array[i]   =  -1*i;
         m_short_array2[i]  =  -2*i;
         m_ushort_array[i]  =   3u*i;
@@ -66,6 +67,7 @@
 
 void cppyy_test_data::destroy_arrays() {
     if (m_owns_arrays == true) {
+        delete[] m_bool_array2;
         delete[] m_short_array2;
         delete[] m_ushort_array2;
         delete[] m_int_array2;
@@ -96,6 +98,8 @@
 double         cppyy_test_data::get_double() { return m_double; }
 cppyy_test_data::what cppyy_test_data::get_enum() { return m_enum; }
 
+bool*           cppyy_test_data::get_bool_array()    { return m_bool_array; }
+bool*           cppyy_test_data::get_bool_array2()   { return m_bool_array2; }
 short*          cppyy_test_data::get_short_array()   { return m_short_array; }
 short*          cppyy_test_data::get_short_array2()  { return m_short_array2; }
 unsigned short* cppyy_test_data::get_ushort_array()  { return m_ushort_array; }
@@ -151,8 +155,19 @@
 void cppyy_test_data::set_pod_ref(const cppyy_test_pod& rp)    { m_pod = rp; }
 void cppyy_test_data::set_pod_ptrptr_in(cppyy_test_pod** ppp)  { m_pod = **ppp; }
 void cppyy_test_data::set_pod_void_ptrptr_in(void** pp)        { m_pod = **((cppyy_test_pod**)pp); }
-void cppyy_test_data::set_pod_ptrptr_out(cppyy_test_pod** ppp) { *ppp = &m_pod; }
-void cppyy_test_data::set_pod_void_ptrptr_out(void** pp)       { *((cppyy_test_pod**)pp) = &m_pod; }
+void cppyy_test_data::set_pod_ptrptr_out(cppyy_test_pod** ppp) { delete *ppp; *ppp = new cppyy_test_pod(m_pod); }
+void cppyy_test_data::set_pod_void_ptrptr_out(void** pp)       { delete *((cppyy_test_pod**)pp);
+                                                                 *((cppyy_test_pod**)pp) = new cppyy_test_pod(m_pod); }
+
+//- passers -----------------------------------------------------------------
+short*          cppyy_test_data::pass_array(short* a)          { return a; }
+unsigned short* cppyy_test_data::pass_array(unsigned short* a) { return a; }
+int*            cppyy_test_data::pass_array(int* a)            { return a; }
+unsigned int*   cppyy_test_data::pass_array(unsigned int* a)   { return a; }
+long*           cppyy_test_data::pass_array(long* a)           { return a; }
+unsigned long*  cppyy_test_data::pass_array(unsigned long* a)  { return a; }
+float*          cppyy_test_data::pass_array(float* a)          { return a; }
+double*         cppyy_test_data::pass_array(double* a)         { return a; }
 
 char                cppyy_test_data::s_char   = 's';
 unsigned char       cppyy_test_data::s_uchar  = 'u';
diff --git a/pypy/module/cppyy/test/datatypes.h b/pypy/module/cppyy/test/datatypes.h
--- a/pypy/module/cppyy/test/datatypes.h
+++ b/pypy/module/cppyy/test/datatypes.h
@@ -15,7 +15,7 @@
     ~cppyy_test_data();
 
 // special cases
-   enum what { kNothing=6, kSomething=111, kLots=42 };
+    enum what { kNothing=6, kSomething=111, kLots=42 };
 
 // helper
     void destroy_arrays();
@@ -36,6 +36,8 @@
     double               get_double();
     what                 get_enum();
 
+    bool*           get_bool_array();
+    bool*           get_bool_array2();
     short*          get_short_array();
     short*          get_short_array2();
     unsigned short* get_ushort_array();
@@ -94,6 +96,25 @@
     void set_pod_ptrptr_out(cppyy_test_pod**);
     void set_pod_void_ptrptr_out(void**);
 
+// passers
+    short*          pass_array(short*);
+    unsigned short* pass_array(unsigned short*);
+    int*            pass_array(int*);
+    unsigned int*   pass_array(unsigned int*);
+    long*           pass_array(long*);
+    unsigned long*  pass_array(unsigned long*);
+    float*          pass_array(float*);
+    double*         pass_array(double*);
+
+    short*          pass_void_array_h(void* a) { return pass_array((short*)a); }
+    unsigned short* pass_void_array_H(void* a) { return pass_array((unsigned short*)a); }
+    int*            pass_void_array_i(void* a) { return pass_array((int*)a); }
+    unsigned int*   pass_void_array_I(void* a) { return pass_array((unsigned int*)a); }
+    long*           pass_void_array_l(void* a) { return pass_array((long*)a); }
+    unsigned long*  pass_void_array_L(void* a) { return pass_array((unsigned long*)a); }
+    float*          pass_void_array_f(void* a) { return pass_array((float*)a); }
+    double*         pass_void_array_d(void* a) { return pass_array((double*)a); }
+
 public:
 // basic types
     bool                 m_bool;
@@ -112,6 +133,8 @@
     what                 m_enum;
 
 // array types
+    bool            m_bool_array[N];
+    bool*           m_bool_array2;
     short           m_short_array[N];
     short*          m_short_array2;
     unsigned short  m_ushort_array[N];
diff --git a/pypy/module/cppyy/test/example01.cxx b/pypy/module/cppyy/test/example01.cxx
--- a/pypy/module/cppyy/test/example01.cxx
+++ b/pypy/module/cppyy/test/example01.cxx
@@ -156,6 +156,8 @@
    return ::globalAddOneToInt(a);
 }
 
+int ns_example01::gMyGlobalInt = 99;
+
 
 // argument passing
 #define typeValueImp(itype, tname)                                            \
diff --git a/pypy/module/cppyy/test/example01.h b/pypy/module/cppyy/test/example01.h
--- a/pypy/module/cppyy/test/example01.h
+++ b/pypy/module/cppyy/test/example01.h
@@ -60,10 +60,11 @@
 };
 
 
-// global functions
+// global functions and data
 int globalAddOneToInt(int a);
 namespace ns_example01 {
     int globalAddOneToInt(int a);
+    extern int gMyGlobalInt;
 }
 
 #define itypeValue(itype, tname) \
@@ -72,6 +73,7 @@
 #define ftypeValue(ftype) \
    ftype ftype##Value(ftype arg0, int argn=0, ftype arg1=1., ftype arg2=2.)
 
+
 // argument passing
 class ArgPasser {        // use a class for now as methptrgetter not
 public:                  // implemented for global functions
diff --git a/pypy/module/cppyy/test/example01.xml b/pypy/module/cppyy/test/example01.xml
--- a/pypy/module/cppyy/test/example01.xml
+++ b/pypy/module/cppyy/test/example01.xml
@@ -11,6 +11,7 @@
 
   <namespace name="ns_example01" />
   <function name="ns_example01::globalAddOneToInt" />
+  <variable name="ns_example01::gMyGlobalInt" />
 
   <class name="ArgPasser" />
 
diff --git a/pypy/module/cppyy/test/example01_LinkDef.h b/pypy/module/cppyy/test/example01_LinkDef.h
--- a/pypy/module/cppyy/test/example01_LinkDef.h
+++ b/pypy/module/cppyy/test/example01_LinkDef.h
@@ -16,4 +16,6 @@
 #pragma link C++ namespace ns_example01;
 #pragma link C++ function ns_example01::globalAddOneToInt(int);
 
+#pragma link C++ variable ns_example01::gMyGlobalInt;
+
 #endif
diff --git a/pypy/module/cppyy/test/fragile.h b/pypy/module/cppyy/test/fragile.h
--- a/pypy/module/cppyy/test/fragile.h
+++ b/pypy/module/cppyy/test/fragile.h
@@ -77,4 +77,14 @@
 
 void fglobal(int, double, char);
 
+namespace nested1 {
+    class A {};
+    namespace nested2 {
+        class A {};
+        namespace nested3 {
+            class A {};
+        } // namespace nested3
+    } // namespace nested2
+} // namespace nested1
+
 } // namespace fragile
diff --git a/pypy/module/cppyy/test/fragile.xml b/pypy/module/cppyy/test/fragile.xml
--- a/pypy/module/cppyy/test/fragile.xml
+++ b/pypy/module/cppyy/test/fragile.xml
@@ -1,8 +1,14 @@
 <lcgdict>
 
   <namespace name="fragile" />
+  <namespace name="fragile::nested1" />
+  <namespace name="fragile::nested1::nested2" />
+  <namespace name="fragile::nested1::nested2::nested3" />
 
   <class pattern="fragile::[A-Z]" />
+  <class name="fragile::nested1::A" />
+  <class name="fragile::nested1::nested2::A" />
+  <class name="fragile::nested1::nested2::nested3::A" />
 
   <variable name="fragile::gI" />
 
diff --git a/pypy/module/cppyy/test/fragile_LinkDef.h b/pypy/module/cppyy/test/fragile_LinkDef.h
--- a/pypy/module/cppyy/test/fragile_LinkDef.h
+++ b/pypy/module/cppyy/test/fragile_LinkDef.h
@@ -5,6 +5,9 @@
 #pragma link off all functions;
 
 #pragma link C++ namespace fragile;
+#pragma link C++ namespace fragile::nested1;
+#pragma link C++ namespace fragile::nested1::nested2;
+#pragma link C++ namespace fragile::nested1::nested2::nested3;
 
 #pragma link C++ class fragile::A;
 #pragma link C++ class fragile::B;
@@ -16,6 +19,9 @@
 #pragma link C++ class fragile::H;
 #pragma link C++ class fragile::I;
 #pragma link C++ class fragile::J;
+#pragma link C++ class fragile::nested1::A;
+#pragma link C++ class fragile::nested1::nested2::A;
+#pragma link C++ class fragile::nested1::nested2::nested3::A;
 
 #pragma link C++ variable fragile::gI;
 
diff --git a/pypy/module/cppyy/test/iotypes.cxx b/pypy/module/cppyy/test/iotypes.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/iotypes.cxx
@@ -0,0 +1,7 @@
+#include "iotypes.h"
+
+const IO::Floats_t& IO::SomeDataObject::get_floats() { return m_floats; }
+const IO::Tuples_t& IO::SomeDataObject::get_tuples() { return m_tuples; }
+
+void IO::SomeDataObject::add_float(float f) { m_floats.push_back(f); }
+void IO::SomeDataObject::add_tuple(const std::vector<float>& t) { m_tuples.push_back(t); }
diff --git a/pypy/module/cppyy/test/iotypes.h b/pypy/module/cppyy/test/iotypes.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/iotypes.h
@@ -0,0 +1,28 @@
+#include <vector>
+
+namespace IO {
+
+typedef std::vector<float>                Floats_t;
+typedef std::vector<std::vector<float> >  Tuples_t;
+
+class SomeDataObject {
+public:
+   const Floats_t& get_floats();
+   const Tuples_t& get_tuples();
+
+public:
+   void add_float(float f);
+   void add_tuple(const std::vector<float>& t);
+
+private:
+   Floats_t m_floats;
+   Tuples_t m_tuples;
+};
+
+struct SomeDataStruct {
+   Floats_t Floats;
+   char     Label[3];
+   int      NLabel;
+};
+
+} // namespace IO
diff --git a/pypy/module/cppyy/test/iotypes.xml b/pypy/module/cppyy/test/iotypes.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/iotypes.xml
@@ -0,0 +1,3 @@
+<lcgdict>
+<!-- empty -->
+</lcgdict>
diff --git a/pypy/module/cppyy/test/iotypes_LinkDef.h b/pypy/module/cppyy/test/iotypes_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/iotypes_LinkDef.h
@@ -0,0 +1,16 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+using namespace std;
+#pragma link C++ class vector<vector<float> >+;
+#pragma link C++ class vector<vector<float> >::iterator;
+#pragma link C++ class vector<vector<float> >::const_iterator;
+
+#pragma link C++ namespace IO;
+#pragma link C++ class IO::SomeDataObject+;
+#pragma link C++ class IO::SomeDataStruct+;
+
+#endif
diff --git a/pypy/module/cppyy/test/simple_class.C b/pypy/module/cppyy/test/simple_class.C
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/simple_class.C
@@ -0,0 +1,15 @@
+class MySimpleBase {
+public:
+    MySimpleBase() {}
+};
+
+class MySimpleDerived : public MySimpleBase {
+public:
+    MySimpleDerived() { m_data = -42; }
+    int get_data() { return m_data; }
+    void set_data(int data) { m_data = data; }
+public:
+    int m_data;
+};
+
+typedef MySimpleDerived MySimpleDerived_t;
diff --git a/pypy/module/cppyy/test/std_streams.xml b/pypy/module/cppyy/test/std_streams.xml
--- a/pypy/module/cppyy/test/std_streams.xml
+++ b/pypy/module/cppyy/test/std_streams.xml
@@ -4,4 +4,6 @@
   <class name = "std::ios_base"/>
   <class name = "std::basic_ios<char,std::char_traits<char> >"/>
 
+  <variable name="std::cout" />
+
 </lcgdict>
diff --git a/pypy/module/cppyy/test/std_streams_LinkDef.h b/pypy/module/cppyy/test/std_streams_LinkDef.h
--- a/pypy/module/cppyy/test/std_streams_LinkDef.h
+++ b/pypy/module/cppyy/test/std_streams_LinkDef.h
@@ -4,6 +4,4 @@
 #pragma link off all classes;
 #pragma link off all functions;
 
-#pragma link C++ class std::ostream;
-
 #endif
diff --git a/pypy/module/cppyy/test/stltypes.cxx b/pypy/module/cppyy/test/stltypes.cxx
--- a/pypy/module/cppyy/test/stltypes.cxx
+++ b/pypy/module/cppyy/test/stltypes.cxx
@@ -1,9 +1,6 @@
 #include "stltypes.h"
 
-#define STLTYPES_EXPLICIT_INSTANTIATION(STLTYPE, TTYPE)                         \
-template class std::STLTYPE< TTYPE >;                                           \
-template class __gnu_cxx::__normal_iterator<TTYPE*, std::STLTYPE< TTYPE > >;    \
-template class __gnu_cxx::__normal_iterator<const TTYPE*, std::STLTYPE< TTYPE > >;\
+#define STLTYPES_EXPLICIT_INSTANTIATION_WITH_COMPS(STLTYPE, TTYPE)              \
 namespace __gnu_cxx {                                                           \
 template bool operator==(const std::STLTYPE< TTYPE >::iterator&,                \
                          const std::STLTYPE< TTYPE >::iterator&);               \
@@ -11,10 +8,8 @@
                          const std::STLTYPE< TTYPE >::iterator&);               \
 }
 
-
-//- explicit instantiations of used types
-STLTYPES_EXPLICIT_INSTANTIATION(vector, int)
-STLTYPES_EXPLICIT_INSTANTIATION(vector, just_a_class)
+//- explicit instantiations of used comparisons
+STLTYPES_EXPLICIT_INSTANTIATION_WITH_COMPS(vector, int)
 
 //- class with lots of std::string handling
 stringy_class::stringy_class(const char* s) : m_string(s) {}
diff --git a/pypy/module/cppyy/test/stltypes.h b/pypy/module/cppyy/test/stltypes.h
--- a/pypy/module/cppyy/test/stltypes.h
+++ b/pypy/module/cppyy/test/stltypes.h
@@ -3,30 +3,50 @@
 #include <string>
 #include <vector>
 
-#define STLTYPES_EXPLICIT_INSTANTIATION_DECL(STLTYPE, TTYPE)                    \
-extern template class std::STLTYPE< TTYPE >;                                    \
-extern template class __gnu_cxx::__normal_iterator<TTYPE*, std::STLTYPE< TTYPE > >;\
-extern template class __gnu_cxx::__normal_iterator<const TTYPE*, std::STLTYPE< TTYPE > >;\
-namespace __gnu_cxx {                                                           \
-extern template bool operator==(const std::STLTYPE< TTYPE >::iterator&,         \
-                         const std::STLTYPE< TTYPE >::iterator&);               \
-extern template bool operator!=(const std::STLTYPE< TTYPE >::iterator&,         \
-                         const std::STLTYPE< TTYPE >::iterator&);               \
-}
-
-
 //- basic example class
 class just_a_class {
 public:
     int m_i;
 };
 
+#define STLTYPE_INSTANTIATION(STLTYPE, TTYPE, N)                             \
+   std::STLTYPE<TTYPE > STLTYPE##_##N;                                       \
+   std::STLTYPE<TTYPE >::iterator STLTYPE##_##N##_i;                         \
+   std::STLTYPE<TTYPE >::const_iterator STLTYPE##_##N##_ci
 
-#ifndef __CINT__
-//- explicit instantiations of used types
-STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, int)
-STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, just_a_class)
-#endif
+//- instantiations of used STL types
+namespace {
+
+    struct _CppyyVectorInstances {
+
+        STLTYPE_INSTANTIATION(vector, int,          1);
+        STLTYPE_INSTANTIATION(vector, float,        2);
+        STLTYPE_INSTANTIATION(vector, double,       3);
+        STLTYPE_INSTANTIATION(vector, just_a_class, 4);
+
+    };
+
+    struct _CppyyListInstances {
+
+        STLTYPE_INSTANTIATION(list, int,          1);
+        STLTYPE_INSTANTIATION(list, float,        2);
+        STLTYPE_INSTANTIATION(list, double,       3);
+
+    };
+
+} // unnamed namespace
+
+#define STLTYPES_EXPLICIT_INSTANTIATION_DECL_COMPS(STLTYPE, TTYPE)           \
+namespace __gnu_cxx {                                                        \
+extern template bool operator==(const std::STLTYPE< TTYPE >::iterator&,      \
+                         const std::STLTYPE< TTYPE >::iterator&);            \
+extern template bool operator!=(const std::STLTYPE< TTYPE >::iterator&,      \
+                         const std::STLTYPE< TTYPE >::iterator&);            \
+}
+
+// comps for int only to allow testing: normal use of vector is looping over a
+// range-checked version of __getitem__
+STLTYPES_EXPLICIT_INSTANTIATION_DECL_COMPS(vector, int)
 
 
 //- class with lots of std::string handling
diff --git a/pypy/module/cppyy/test/stltypes.xml b/pypy/module/cppyy/test/stltypes.xml
--- a/pypy/module/cppyy/test/stltypes.xml
+++ b/pypy/module/cppyy/test/stltypes.xml
@@ -3,12 +3,17 @@
   <namespace name="std" />
 
   <class pattern="std::vector<*>" />
+  <class pattern="std::vector<*>::iterator" />
+  <class pattern="std::vector<*>::const_iterator" />
+
+  <class pattern="std::list<*>" />
+  <class pattern="std::list<*>::iterator" />
+  <class pattern="std::list<*>::const_iterator" />
+  <class name="std::__detail::_List_node_base" />
+
   <class pattern="__gnu_cxx::__normal_iterator<*>" />
-  <class pattern="__gnu_cxx::new_allocator<*>" />
-  <class pattern="std::_Vector_base<*>" />
-  <class pattern="std::_Vector_base<*>::_Vector_impl" />
-  <class pattern="std::allocator<*>" />
 
+  <!-- the following are for testing, not for iteration -->
   <function name="__gnu_cxx::operator=="/>
   <function name="__gnu_cxx::operator!="/>
 
diff --git a/pypy/module/cppyy/test/test_advancedcpp.py b/pypy/module/cppyy/test/test_advancedcpp.py
--- a/pypy/module/cppyy/test/test_advancedcpp.py
+++ b/pypy/module/cppyy/test/test_advancedcpp.py
@@ -7,7 +7,7 @@
 currpath = py.path.local(__file__).dirpath()
 test_dct = str(currpath.join("advancedcppDict.so"))
 
-space = gettestobjspace(usemodules=['cppyy'])
+space = gettestobjspace(usemodules=['cppyy', 'array'])
 
 def setup_module(mod):
     if sys.platform == 'win32':
@@ -31,31 +31,42 @@
         """Test usage of default arguments"""
 
         import cppyy
-        defaulter = cppyy.gbl.defaulter
+        def test_defaulter(n, t):
+            defaulter = getattr(cppyy.gbl, '%s_defaulter' % n)
 
-        d = defaulter()
-        assert d.m_a == 11
-        assert d.m_b == 22
-        assert d.m_c == 33
-        d.destruct()
+            d = defaulter()
+            assert d.m_a == t(11)
+            assert d.m_b == t(22)
+            assert d.m_c == t(33)
+            d.destruct()
 
-        d = defaulter(0)
-        assert d.m_a ==  0
-        assert d.m_b == 22
-        assert d.m_c == 33
-        d.destruct()
+            d = defaulter(0)
+            assert d.m_a ==  t(0)
+            assert d.m_b == t(22)
+            assert d.m_c == t(33)
+            d.destruct()
 
-        d = defaulter(1, 2)
-        assert d.m_a ==  1
-        assert d.m_b ==  2
-        assert d.m_c == 33
-        d.destruct()
+            d = defaulter(1, 2)
+            assert d.m_a ==  t(1)
+            assert d.m_b ==  t(2)
+            assert d.m_c == t(33)
+            d.destruct()
 
-        d = defaulter(3, 4, 5)
-        assert d.m_a ==  3
-        assert d.m_b ==  4
-        assert d.m_c ==  5
-        d.destruct()
+            d = defaulter(3, 4, 5)
+            assert d.m_a ==  t(3)
+            assert d.m_b ==  t(4)
+            assert d.m_c ==  t(5)
+            d.destruct()
+        test_defaulter('short', int)
+        test_defaulter('ushort', int)
+        test_defaulter('int', int)
+        test_defaulter('uint', int)
+        test_defaulter('long', long)
+        test_defaulter('ulong', long)
+        test_defaulter('llong', long)
+        test_defaulter('ullong', long)
+        test_defaulter('float', float)
+        test_defaulter('double', float)
 
     def test02_simple_inheritance(self):
         """Test binding of a basic inheritance structure"""
@@ -372,6 +383,20 @@
         assert cppyy.addressof(o) == pp.gime_address_ptr_ptr(o)
         assert cppyy.addressof(o) == pp.gime_address_ptr_ref(o)
 
+        import array
+        addressofo = array.array('l', [cppyy.addressof(o)])
+        assert addressofo.buffer_info()[0] == pp.gime_address_ptr_ptr(addressofo)
+
+        assert 0 == pp.gime_address_ptr(0)
+        assert 0 == pp.gime_address_ptr(None)
+
+        ptr = cppyy.bind_object(0, some_concrete_class)
+        assert cppyy.addressof(ptr) == 0
+        pp.set_address_ptr_ref(ptr)
+        assert cppyy.addressof(ptr) == 0x1234
+        pp.set_address_ptr_ptr(ptr)
+        assert cppyy.addressof(ptr) == 0x4321
+
     def test09_opaque_pointer_assing(self):
         """Test passing around of opaque pointers"""
 
diff --git a/pypy/module/cppyy/test/test_cint.py b/pypy/module/cppyy/test/test_cint.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_cint.py
@@ -0,0 +1,289 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+
+# These tests are for the CINT backend only (they exercise ROOT features
+# and classes that are not loaded/available with the Reflex backend). At
+# some point, these tests are likely covered by the CLang/LLVM backend.
+from pypy.module.cppyy import capi
+if capi.identify() != 'CINT':
+    py.test.skip("backend-specific: CINT-only tests")
+
+currpath = py.path.local(__file__).dirpath()
+iotypes_dct = str(currpath.join("iotypesDict.so"))
+
+space = gettestobjspace(usemodules=['cppyy'])
+
+def setup_module(mod):
+    if sys.platform == 'win32':
+        py.test.skip("win32 not supported so far")
+    err = os.system("cd '%s' && make CINT=t iotypesDict.so" % currpath)
+    if err:
+        raise OSError("'make' failed (see stderr)")
+
+class AppTestCINT:
+    def setup_class(cls):
+        cls.space = space
+
+    def test01_globals(self):
+        """Test the availability of ROOT globals"""
+
+        import cppyy
+
+        assert cppyy.gbl.gROOT
+        assert cppyy.gbl.gApplication
+        assert cppyy.gbl.gSystem
+        assert cppyy.gbl.TInterpreter.Instance()           # compiled
+        assert cppyy.gbl.TInterpreter                      # interpreted
+        assert cppyy.gbl.TDirectory.CurrentDirectory()     # compiled
+        assert cppyy.gbl.TDirectory                        # interpreted
+
+    def test02_write_access_to_globals(self):
+        """Test overwritability of ROOT globals"""
+
+        import cppyy
+
+        oldval = cppyy.gbl.gDebug
+        assert oldval != 3
+
+        proxy = cppyy.gbl.__class__.gDebug
+        cppyy.gbl.gDebug = 3
+        assert proxy.__get__(proxy) == 3
+
+        # this is where this test differs from test03_write_access_to_globals
+        # in test_pythonify.py
+        cppyy.gbl.gROOT.ProcessLine('int gDebugCopy = gDebug;')
+        assert cppyy.gbl.gDebugCopy == 3
+
+        cppyy.gbl.gDebug = oldval
+
+    def test03_create_access_to_globals(self):
+        """Test creation and access of new ROOT globals"""
+
+        import cppyy
+
+        cppyy.gbl.gROOT.ProcessLine('double gMyOwnGlobal = 3.1415')
+        assert cppyy.gbl.gMyOwnGlobal == 3.1415
+
+        proxy = cppyy.gbl.__class__.gMyOwnGlobal
+        assert proxy.__get__(proxy) == 3.1415
+
+    def test04_auto_loading(self):
+        """Test auto-loading by retrieving a non-preloaded class"""
+
+        import cppyy
+
+        l = cppyy.gbl.TLorentzVector()
+        assert isinstance(l, cppyy.gbl.TLorentzVector)
+
+    def test05_macro_loading(self):
+        """Test accessibility to macro classes"""
+
+        import cppyy
+
+        loadres = cppyy.gbl.gROOT.LoadMacro('simple_class.C')
+        assert loadres == 0
+
+        base = cppyy.gbl.MySimpleBase
+        simple = cppyy.gbl.MySimpleDerived
+        simple_t = cppyy.gbl.MySimpleDerived_t
+
+        assert issubclass(simple, base)
+        assert simple is simple_t
+
+        c = simple()
+        assert isinstance(c, simple)
+        assert c.m_data == c.get_data()
+
+        c.set_data(13)
+        assert c.m_data == 13
+        assert c.get_data() == 13
+
+
+class AppTestCINTPythonizations:
+    def setup_class(cls):
+        cls.space = space
+
+    def test03_TVector(self):
+        """Test TVector2/3/T behavior"""
+
+        import cppyy, math
+
+        N = 51
+
+        # TVectorF is a typedef of floats
+        v = cppyy.gbl.TVectorF(N)
+        for i in range(N):
+             v[i] = i*i
+
+        assert len(v) == N
+        for j in v:
+             assert round(v[int(math.sqrt(j)+0.5)]-j, 5) == 0.
+
+
+class AppTestCINTTTree:
+    def setup_class(cls):
+        cls.space = space
+        cls.w_N = space.wrap(5)
+        cls.w_M = space.wrap(10)
+        cls.w_fname = space.wrap("test.root")
+        cls.w_tname = space.wrap("test")
+        cls.w_title = space.wrap("test tree")
+        cls.w_iotypes = cls.space.appexec([], """():
+            import cppyy
+            return cppyy.load_reflection_info(%r)""" % (iotypes_dct,))
+
+    def test01_write_stdvector(self):
+        """Test writing of a single branched TTree with an std::vector<double>"""
+
+        from cppyy import gbl               # bootstraps, only needed for tests
+        from cppyy.gbl import TFile, TTree
+        from cppyy.gbl.std import vector
+
+        f = TFile(self.fname, "RECREATE")
+        mytree = TTree(self.tname, self.title)
+        mytree._python_owns = False
+
+        v = vector("double")()
+        raises(TypeError, TTree.Branch, None, "mydata", v.__class__.__name__, v)
+        raises(TypeError, TTree.Branch, v, "mydata", v.__class__.__name__, v)
+
+        mytree.Branch("mydata", v.__class__.__name__, v)
+
+        for i in range(self.N):
+            for j in range(self.M):
+                v.push_back(i*self.M+j)
+            mytree.Fill()
+            v.clear()
+        f.Write()
+        f.Close()
+
+    def test02_read_stdvector(self):
+        """Test reading of a single branched TTree with an std::vector<double>"""
+
+        from cppyy import gbl
+        from cppyy.gbl import TFile
+
+        f = TFile(self.fname)
+        mytree = f.Get(self.tname)
+
+        i = 0
+        for event in mytree:
+            assert len(event.mydata) == self.M
+            for entry in event.mydata:
+                assert i == int(entry)
+                i += 1
+        assert i == self.N * self.M
+
+        f.Close()
+
+    def test03_write_some_data_object(self):
+        """Test writing of a complex data object"""
+
+        from cppyy import gbl
+        from cppyy.gbl import TFile, TTree, IO
+        from cppyy.gbl.IO import SomeDataObject
+
+        f = TFile(self.fname, "RECREATE")
+        mytree = TTree(self.tname, self.title)
+
+        d = SomeDataObject()
+        b = mytree.Branch("data", d)
+        mytree._python_owns = False
+        assert b
+
+        for i in range(self.N):
+            for j in range(self.M):
+                d.add_float(i*self.M+j)
+            d.add_tuple(d.get_floats())
+
+            mytree.Fill()
+
+        f.Write()
+        f.Close()
+
+    def test04_read_some_data_object(self):
+        """Test reading of a complex data object"""
+
+        from cppyy import gbl
+        from cppyy.gbl import TFile
+
+        f = TFile(self.fname)
+        mytree = f.Get(self.tname)
+
+        j = 1
+        for event in mytree:
+            i = 0
+            assert len(event.data.get_floats()) == j*self.M
+            for entry in event.data.get_floats():
+                assert i == int(entry)
+                i += 1
+
+            k = 1
+            assert len(event.data.get_tuples()) == j
+            for mytuple in event.data.get_tuples():
+                i = 0
+                assert len(mytuple) == k*self.M
+                for entry in mytuple:
+                    assert i == int(entry)
+                    i += 1
+                k += 1
+            j += 1
+        assert j-1 == self.N
+        #
+        f.Close()
+
+    def test05_branch_activation(self):
+        """Test of automatic branch activation"""
+
+        from cppyy import gbl               # bootstraps, only needed for tests
+        from cppyy.gbl import TFile, TTree
+        from cppyy.gbl.std import vector
+
+        L = 5
+
+        # writing
+        f = TFile(self.fname, "RECREATE")
+        mytree = TTree(self.tname, self.title)
+        mytree._python_owns = False
+
+        for i in range(L):
+            v = vector("double")()
+            mytree.Branch("mydata_%d"%i, v.__class__.__name__, v)
+            mytree.__dict__["v_%d"%i] = v
+
+        for i in range(self.N):
+            for k in range(L):
+                v = mytree.__dict__["v_%d"%k]
+                for j in range(self.M):
+                    mytree.__dict__["v_%d"%k].push_back(i*self.M+j*L+k)
+            mytree.Fill()
+            for k in range(L):
+                v = mytree.__dict__["v_%d"%k]
+                v.clear()
+        f.Write()
+        f.Close()
+
+        del mytree, f
+        import gc
+        gc.collect()
+
+        # reading
+        f = TFile(self.fname)
+        mytree = f.Get(self.tname)
+
+        # force (initial) disabling of all branches
+        mytree.SetBranchStatus("*",0);
+
+        i = 0
+        for event in mytree:
+            for k in range(L):
+                j = 0
+                data = getattr(mytree, "mydata_%d"%k)
+                assert len(data) == self.M
+                for entry in data:
+                    assert entry == i*self.M+j*L+k
+                    j += 1
+                assert j == self.M
+            i += 1
+        assert i == self.N
+
diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py
--- a/pypy/module/cppyy/test/test_cppyy.py
+++ b/pypy/module/cppyy/test/test_cppyy.py
@@ -26,7 +26,7 @@
         func, = adddouble.functions
         assert func.executor is None
         func._setup(None)     # creates executor
-        assert isinstance(func.executor, executor.DoubleExecutor)
+        assert isinstance(func.executor, executor._executors['double'])
         assert func.arg_defs == [("double", "")]
 
 
diff --git a/pypy/module/cppyy/test/test_datatypes.py b/pypy/module/cppyy/test/test_datatypes.py
--- a/pypy/module/cppyy/test/test_datatypes.py
+++ b/pypy/module/cppyy/test/test_datatypes.py
@@ -5,7 +5,7 @@
 currpath = py.path.local(__file__).dirpath()
 test_dct = str(currpath.join("datatypesDict.so"))
 
-space = gettestobjspace(usemodules=['cppyy', 'array'])
+space = gettestobjspace(usemodules=['cppyy', 'array', '_rawffi'])
 
 def setup_module(mod):
     if sys.platform == 'win32':
@@ -63,6 +63,10 @@
         # reding of array types
         for i in range(self.N):
             # reading of integer array types
+            assert c.m_bool_array[i]        ==   bool(i%2)
+            assert c.get_bool_array()[i]    ==   bool(i%2)
+            assert c.m_bool_array2[i]       ==   bool((i+1)%2)
+            assert c.get_bool_array2()[i]   ==   bool((i+1)%2)
             assert c.m_short_array[i]       ==  -1*i
             assert c.get_short_array()[i]   ==  -1*i
             assert c.m_short_array2[i]      ==  -2*i
@@ -194,16 +198,39 @@
 
         c.destruct()
 
-    def test04_respect_privacy(self):
-        """Test that privacy settings are respected"""
+    def test04_array_passing(self):
+        """Test passing of array arguments"""
 
-        import cppyy
+        import cppyy, array, sys
         cppyy_test_data = cppyy.gbl.cppyy_test_data
 
         c = cppyy_test_data()
         assert isinstance(c, cppyy_test_data)
 
-        raises(AttributeError, getattr, c, 'm_owns_arrays')
+        a = range(self.N)
+        # test arrays in mixed order, to give overload resolution a workout
+        for t in ['d', 'i', 'f', 'H', 'I', 'h', 'L', 'l' ]:
+            b = array.array(t, a)
+
+            # typed passing
+            ca = c.pass_array(b)
+            assert type(ca[0]) == type(b[0])
+            assert len(b) == self.N
+            for i in range(self.N):
+                assert ca[i] == b[i]
+
+            # void* passing
+            ca = eval('c.pass_void_array_%s(b)' % t)
+            assert type(ca[0]) == type(b[0])
+            assert len(b) == self.N
+            for i in range(self.N):
+                assert ca[i] == b[i]
+
+        # NULL/None passing (will use short*)
+        assert not c.pass_array(0)
+        raises(Exception, c.pass_array(0).__getitem__, 0)    # raises SegfaultException
+        assert not c.pass_array(None)
+        raises(Exception, c.pass_array(None).__getitem__, 0) # id.
 
         c.destruct()
 
@@ -524,3 +551,38 @@
         assert c.m_pod.m_double == 3.14
         assert p.m_int == 888
         assert p.m_double == 3.14
+
+    def test14_respect_privacy(self):
+        """Test that privacy settings are respected"""
+
+        import cppyy
+        cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+        c = cppyy_test_data()
+        assert isinstance(c, cppyy_test_data)
+
+        raises(AttributeError, getattr, c, 'm_owns_arrays')
+
+        c.destruct()
+
+    def test15_buffer_reshaping(self):
+        """Test usage of buffer sizing"""
+
+        import cppyy
+        cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+        c = cppyy_test_data()
+        for func in ['get_bool_array',   'get_bool_array2',
+                     'get_ushort_array', 'get_ushort_array2',
+                     'get_int_array',    'get_int_array2',
+                     'get_uint_array',   'get_uint_array2',
+                     'get_long_array',   'get_long_array2',
+                     'get_ulong_array',  'get_ulong_array2']:
+            arr = getattr(c, func)()
+            arr = arr.shape.fromaddress(arr.itemaddress(0), self.N)
+            assert len(arr) == self.N
+
+            l = list(arr)
+            for i in range(self.N):
+                assert arr[i] == l[i]
+
diff --git a/pypy/module/cppyy/test/test_fragile.py b/pypy/module/cppyy/test/test_fragile.py
--- a/pypy/module/cppyy/test/test_fragile.py
+++ b/pypy/module/cppyy/test/test_fragile.py
@@ -1,6 +1,7 @@
 import py, os, sys
 from pypy.conftest import gettestobjspace
 
+from pypy.module.cppyy import capi
 
 currpath = py.path.local(__file__).dirpath()
 test_dct = str(currpath.join("fragileDict.so"))
@@ -19,7 +20,8 @@
         cls.space = space
         env = os.environ
         cls.w_test_dct  = space.wrap(test_dct)
-        cls.w_datatypes = cls.space.appexec([], """():
+        cls.w_capi = space.wrap(capi)
+        cls.w_fragile = cls.space.appexec([], """():
             import cppyy
             return cppyy.load_reflection_info(%r)""" % (test_dct, ))
 
@@ -194,3 +196,61 @@
 
         f = fragile.fglobal
         assert f.__doc__ == "void fragile::fglobal(int, double, char)"
+
+    def test11_dir(self):
+        """Test __dir__ method"""
+
+        import cppyy
+
+        if self.capi.identify() == 'CINT':   # CINT only support classes on global space
+            members = dir(cppyy.gbl)
+            assert 'TROOT' in members
+            assert 'TSystem' in members
+            assert 'TClass' in members
+            members = dir(cppyy.gbl.fragile)
+        else:
+            members = dir(cppyy.gbl.fragile)
+            assert 'A' in members
+            assert 'B' in members
+            assert 'C' in members
+            assert 'D' in members            # classes
+
+            assert 'nested1' in members          # namespace
+
+        assert 'fglobal' in members          # function
+        assert 'gI'in members                # variable
+
+    def test12_imports(self):
+        """Test ability to import from namespace (or fail with ImportError)"""
+
+        import cppyy
+
+        # TODO: namespaces aren't loaded (and thus not added to sys.modules)
+        # with just the from ... import statement; actual use is needed
+        from cppyy.gbl import fragile
+
+        def fail_import():
+            from cppyy.gbl import does_not_exist
+        raises(ImportError, fail_import)
+
+        from cppyy.gbl.fragile import A, B, C, D
+        assert cppyy.gbl.fragile.A is A
+        assert cppyy.gbl.fragile.B is B
+        assert cppyy.gbl.fragile.C is C
+        assert cppyy.gbl.fragile.D is D
+
+        # according to warnings, can't test "import *" ...
+
+        from cppyy.gbl.fragile import nested1
+        assert cppyy.gbl.fragile.nested1 is nested1
+
+        from cppyy.gbl.fragile.nested1 import A, nested2
+        assert cppyy.gbl.fragile.nested1.A is A
+        assert cppyy.gbl.fragile.nested1.nested2 is nested2
+
+        from cppyy.gbl.fragile.nested1.nested2 import A, nested3
+        assert cppyy.gbl.fragile.nested1.nested2.A is A
+        assert cppyy.gbl.fragile.nested1.nested2.nested3 is nested3
+
+        from cppyy.gbl.fragile.nested1.nested2.nested3 import A
+        assert cppyy.gbl.fragile.nested1.nested2.nested3.A is nested3.A
diff --git a/pypy/module/cppyy/test/test_pythonify.py b/pypy/module/cppyy/test/test_pythonify.py
--- a/pypy/module/cppyy/test/test_pythonify.py
+++ b/pypy/module/cppyy/test/test_pythonify.py
@@ -309,6 +309,20 @@
         assert hasattr(z, 'myint')
         assert z.gime_z_(z)
 
+    def test14_bound_unbound_calls(self):
+        """Test (un)bound method calls"""
+
+        import cppyy
+
+        raises(TypeError, cppyy.gbl.example01.addDataToInt, 1)
+
+        meth = cppyy.gbl.example01.addDataToInt
+        raises(TypeError, meth)
+        raises(TypeError, meth, 1)
+
+        e = cppyy.gbl.example01(2)
+        assert 5 == meth(e, 3)
+
 
 class AppTestPYTHONIFY_UI:
     def setup_class(cls):
@@ -345,3 +359,17 @@
 
         example01_pythonize = 1
         raises(TypeError, cppyy.add_pythonization, 'example01', example01_pythonize)
+
+    def test03_write_access_to_globals(self):
+        """Test overwritability of globals"""
+
+        import cppyy
+
+        oldval = cppyy.gbl.ns_example01.gMyGlobalInt
+        assert oldval == 99
+
+        proxy = cppyy.gbl.ns_example01.__class__.gMyGlobalInt
+        cppyy.gbl.ns_example01.gMyGlobalInt = 3
+        assert proxy.__get__(proxy) == 3
+
+        cppyy.gbl.ns_example01.gMyGlobalInt = oldval
diff --git a/pypy/module/cppyy/test/test_stltypes.py b/pypy/module/cppyy/test/test_stltypes.py
--- a/pypy/module/cppyy/test/test_stltypes.py
+++ b/pypy/module/cppyy/test/test_stltypes.py
@@ -17,15 +17,14 @@
 class AppTestSTLVECTOR:
     def setup_class(cls):
         cls.space = space
-        env = os.environ
         cls.w_N = space.wrap(13)
         cls.w_test_dct  = space.wrap(test_dct)
         cls.w_stlvector = cls.space.appexec([], """():
             import cppyy
             return cppyy.load_reflection_info(%r)""" % (test_dct, ))
 
-    def test01_builtin_type_vector_type(self):
-        """Test access to an std::vector<int>"""
+    def test01_builtin_type_vector_types(self):
+        """Test access to std::vector<int>/std::vector<double>"""
 
         import cppyy
 
@@ -34,48 +33,46 @@
 
         assert callable(cppyy.gbl.std.vector)
 
-        tv1 = getattr(cppyy.gbl.std, 'vector<int>')
-        tv2 = cppyy.gbl.std.vector('int')
+        type_info = (
+            ("int",     int),
+            ("float",   "float"),
+            ("double",  "double"),
+        )
 
-        assert tv1 is tv2
+        for c_type, p_type in type_info:
+            tv1 = getattr(cppyy.gbl.std, 'vector<%s>' % c_type)
+            tv2 = cppyy.gbl.std.vector(p_type)
+            assert tv1 is tv2
+            assert tv1.iterator is cppyy.gbl.std.vector(p_type).iterator
 
-        assert cppyy.gbl.std.vector(int).iterator is cppyy.gbl.std.vector(int).iterator
+            #----- 
+            v = tv1(); v += range(self.N)    # default args from Reflex are useless :/
+            if p_type == int:                # only type with == and != reflected in .xml
+                assert v.begin().__eq__(v.begin())
+                assert v.begin() == v.begin()
+                assert v.end() == v.end()
+                assert v.begin() != v.end()
+                assert v.end() != v.begin()
 
-        #-----
-        v = tv1(self.N)
-        # TODO: get the following in order
-        #assert v.begin().__eq__(v.begin())
-        #assert v.begin() == v.begin()
-        #assert v.end() == v.end()
-        #assert v.begin() != v.end()
-        #assert v.end() != v.begin()
+            #-----
+            for i in range(self.N):
+                v[i] = i
+                assert v[i] == i
+                assert v.at(i) == i
 
-        #-----
-        for i in range(self.N):
-          # TODO:
-          #  v[i] = i
-          #  assert v[i] == i
-          #  assert v.at(i) == i
-            pass
+            assert v.size() == self.N
+            assert len(v) == self.N
 
-        assert v.size() == self.N
-        assert len(v) == self.N
-        v.destruct()
+            #-----
+            v = tv1()
+            for i in range(self.N):
+                v.push_back(i)
+                assert v.size() == i+1
+                assert v.at(i) == i
+                assert v[i] == i
 
-        #-----
-        v = tv1()
-        for i in range(self.N):
-            v.push_back(i)
-            assert v.size() == i+1
-            assert v.at(i) == i
-            assert v[i] == i
-
-        return
-
-        assert v.size() == self.N
-        assert len(v) == self.N
-        v.destruct()
-
+            assert v.size() == self.N
+            assert len(v) == self.N
 
     def test02_user_type_vector_type(self):
         """Test access to an std::vector<just_a_class>"""
@@ -207,7 +204,6 @@
 class AppTestSTLSTRING:
     def setup_class(cls):
         cls.space = space
-        env = os.environ
         cls.w_test_dct  = space.wrap(test_dct)
         cls.w_stlstring = cls.space.appexec([], """():
             import cppyy
@@ -282,3 +278,59 @@
         c.set_string1(s)
         assert t0 == c.get_string1()
         assert s == c.get_string1()
+
+
+class AppTestSTLSTRING:
+    def setup_class(cls):
+        cls.space = space
+        cls.w_N = space.wrap(13)
+        cls.w_test_dct  = space.wrap(test_dct)
+        cls.w_stlstring = cls.space.appexec([], """():
+            import cppyy
+            return cppyy.load_reflection_info(%r)""" % (test_dct, ))
+
+    def test01_builtin_list_type(self):
+        """Test access to a list<int>"""
+
+        import cppyy
+        from cppyy.gbl import std
+
+        type_info = (
+            ("int",     int),
+            ("float",   "float"),
+            ("double",  "double"),
+        )
+
+        for c_type, p_type in type_info:
+            tl1 = getattr(std, 'list<%s>' % c_type)
+            tl2 = cppyy.gbl.std.list(p_type)
+            assert tl1 is tl2
+            assert tl1.iterator is cppyy.gbl.std.list(p_type).iterator
+
+            #-----
+            a = tl1()
+            for i in range(self.N):
+                a.push_back( i )
+
+            assert len(a) == self.N
+            assert 11 < self.N
+            assert 11 in a
+
+            #-----
+            ll = list(a)
+            for i in range(self.N):
+                assert ll[i] == i
+
+            for val in a:
+                assert ll[ll.index(val)] == val
+
+    def test02_empty_list_type(self):
+        """Test behavior of empty list<int>"""
+
+        import cppyy
+        from cppyy.gbl import std
+
+        a = std.list(int)()
+        for arg in a:
+           pass
+
diff --git a/pypy/module/cppyy/test/test_streams.py b/pypy/module/cppyy/test/test_streams.py
--- a/pypy/module/cppyy/test/test_streams.py
+++ b/pypy/module/cppyy/test/test_streams.py
@@ -18,14 +18,13 @@
     def setup_class(cls):
         cls.space = space
         env = os.environ
-        cls.w_N = space.wrap(13)
         cls.w_test_dct  = space.wrap(test_dct)
-        cls.w_datatypes = cls.space.appexec([], """():
+        cls.w_streams = cls.space.appexec([], """():
             import cppyy
             return cppyy.load_reflection_info(%r)""" % (test_dct, ))
 
     def test01_std_ostream(self):
-        """Test access to an std::vector<int>"""
+        """Test availability of std::ostream"""
 
         import cppyy
 
@@ -34,3 +33,9 @@
 
         assert callable(cppyy.gbl.std.ostream)
 
+    def test02_std_cout(self):
+        """Test access to std::cout"""
+
+        import cppyy
+
+        assert not (cppyy.gbl.std.cout is None)
diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py
--- a/pypy/module/cppyy/test/test_zjit.py
+++ b/pypy/module/cppyy/test/test_zjit.py
@@ -6,6 +6,9 @@
 from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root
 
 from pypy.module.cppyy import interp_cppyy, capi
+# These tests are for the backend that support the fast path only.
+if capi.identify() == 'CINT':
+    py.test.skip("CINT does not support fast path")
 
 # load cpyext early, or its global vars are counted as leaks in the test
 # (note that the module is not otherwise used in the test itself)
@@ -44,6 +47,12 @@
         self.__name__ = name
     def getname(self, space, name):
         return self.name
+class FakeBuffer(FakeBase):
+    typedname = "buffer"
+    def __init__(self, val):
+        self.val = val
+    def get_raw_address(self):
+        raise ValueError("no raw buffer")
 class FakeException(FakeType):
     def __init__(self, name):
         FakeType.__init__(self, name)
@@ -117,6 +126,9 @@
     def interpclass_w(self, w_obj):
         return w_obj
 
+    def buffer_w(self, w_obj):
+        return FakeBuffer(w_obj)
+
     def exception_match(self, typ, sub):
         return typ is sub
 
@@ -143,10 +155,16 @@
     r_longlong_w = int_w
     r_ulonglong_w = uint_w
 
+    def is_(self, w_obj1, w_obj2):
+        return w_obj1 is w_obj2
+
     def isinstance_w(self, w_obj, w_type):
         assert isinstance(w_obj, FakeBase)
         return w_obj.typename == w_type.name
 
+    def is_true(self, w_obj):
+        return not not w_obj
+
     def type(self, w_obj):
         return FakeType("fake")
 
@@ -169,9 +187,6 @@
 
 class TestFastPathJIT(LLJitMixin):
     def _run_zjit(self, method_name):
-        if capi.identify() == 'CINT':   # CINT does not support fast path
-            return
-
         space = FakeSpace()
         drv = jit.JitDriver(greens=[], reds=["i", "inst", "cppmethod"])
         def f():
diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -28,7 +28,6 @@
 
 
 # import these modules to register api functions by side-effect
-import pypy.module.cpyext.thread
 import pypy.module.cpyext.pyobject
 import pypy.module.cpyext.boolobject
 import pypy.module.cpyext.floatobject
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -48,8 +48,10 @@
 pypydir = py.path.local(autopath.pypydir)
 include_dir = pypydir / 'module' / 'cpyext' / 'include'
 source_dir = pypydir / 'module' / 'cpyext' / 'src'
+translator_c_dir = pypydir / 'translator' / 'c'
 include_dirs = [
     include_dir,
+    translator_c_dir,
     udir,
     ]
 


More information about the pypy-commit mailing list