Commits

Brian Kearns committed 82aedd1 Merge

merge default

Comments (0)

Files changed (58)

pypy/doc/release-2.3.0.rst

+=======================================
+PyPy 2.3 - XXXX TODO
+=======================================
+
+We're pleased to announce PyPy 2.3, which targets version 2.7.6 of the Python
+language. This release updates the stdlib from 2.7.3, jumping directly to 2.7.6.
+
+This release also contains several bugfixes and performance improvements. 
+
+You can download the PyPy 2.3 release here:
+
+    http://pypy.org/download.html
+
+We would like to thank our donors for the continued support of the PyPy
+project. We showed quite a bit of progress on all three projects (see below)
+and we're slowly running out of funds.
+Please consider donating more so we can finish those projects!  The three
+projects are:
+
+* Py3k (supporting Python 3.x): the release PyPy3 2.2 is imminent.
+
+* STM (software transactional memory): a preview will be released very soon,
+  as soon as we fix a few bugs
+
+* NumPy: the work done is included in the PyPy 2.2 release. More details below.
+
+.. _`Raspberry Pi Foundation`: http://www.raspberrypi.org
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 2.2 and cpython 2.7.2`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 64, Windows
+32, or ARM (ARMv6 or ARMv7, with VFPv3).
+
+Work on the native Windows 64 is still stalling, we would welcome a volunteer
+to handle that.
+
+.. _`pypy 2.2 and cpython 2.7.2`: http://speed.pypy.org
+
+Highlights
+==========
+
+* Our Garbage Collector is now "incremental".  It should avoid almost
+  all pauses due to a major collection taking place.  Previously, it
+  would pause the program (rarely) to walk all live objects, which
+  could take arbitrarily long if your process is using a whole lot of
+  RAM.  Now the same work is done in steps.  This should make PyPy
+  more responsive, e.g. in games.  There are still other pauses, from
+  the GC and the JIT, but they should be on the order of 5
+  milliseconds each.
+
+* The JIT counters for hot code were never reset, which meant that a
+  process running for long enough would eventually JIT-compile more
+  and more rarely executed code.  Not only is it useless to compile
+  such code, but as more compiled code means more memory used, this
+  gives the impression of a memory leak.  This has been tentatively
+  fixed by decreasing the counters from time to time.
+
+* NumPy has been split: now PyPy only contains the core module, called
+  ``_numpypy``.  The ``numpy`` module itself has been moved to
+  ``https://bitbucket.org/pypy/numpy`` and ``numpypy`` disappeared.
+  You need to install NumPy separately with a virtualenv:
+  ``pip install git+https://bitbucket.org/pypy/numpy.git``;
+  or directly:
+  ``git clone https://bitbucket.org/pypy/numpy.git``;
+  ``cd numpy``; ``pypy setup.py install``.
+
+* non-inlined calls have less overhead
+
+* Things that use ``sys.set_trace`` are now JITted (like coverage)
+
+* JSON decoding is now very fast (JSON encoding was already very fast)
+
+* various buffer copying methods experience speedups (like list-of-ints to
+  ``int[]`` buffer from cffi)
+
+* We finally wrote (hopefully) all the missing ``os.xxx()`` functions,
+  including ``os.startfile()`` on Windows and a handful of rare ones
+  on Posix.
+
+* numpy has a rudimentary C API that cooperates with ``cpyext``
+
+Cheers,
+Armin Rigo and Maciej Fijalkowski

pypy/doc/whatsnew-head.rst

 .. this is a revision shortly after release-2.3.x
 .. startrev: ba569fe1efdb
 
-
-
 .. branch: small-unroll-improvements
 Improve optimiziation of small allocation-heavy loops in the JIT
+
+.. branch: reflex-support

pypy/module/_sre/interp_sre.py

 
 def slice_w(space, ctx, start, end, w_default):
     if 0 <= start <= end:
-        if isinstance(ctx, rsre_core.StrMatchContext):
-            return space.wrap(ctx._string[start:end])
+        if isinstance(ctx, rsre_core.BufMatchContext):
+            return space.wrap(ctx._buffer.getslice(start, end, 1, end-start))
         elif isinstance(ctx, rsre_core.UnicodeMatchContext):
             return space.wrap(ctx._unicodestr[start:end])
         else:
                              space.wrap("cannot copy this pattern object"))
 
     def make_ctx(self, w_string, pos=0, endpos=sys.maxint):
-        """Make a StrMatchContext or a UnicodeMatchContext for searching
+        """Make a BufMatchContext or a UnicodeMatchContext for searching
         in the given w_string object."""
         space = self.space
         if pos < 0:
             return rsre_core.UnicodeMatchContext(self.code, unicodestr,
                                                  pos, endpos, self.flags)
         else:
-            str = space.bufferstr_w(w_string)
-            if pos > len(str):
-                pos = len(str)
-            if endpos > len(str):
-                endpos = len(str)
-            return rsre_core.StrMatchContext(self.code, str,
+            buf = space.buffer_w(w_string)
+            size = buf.getlength()
+            assert size >= 0
+            if pos > size:
+                pos = size
+            if endpos > size:
+                endpos = size
+            return rsre_core.BufMatchContext(self.code, buf,
                                              pos, endpos, self.flags)
 
     def getmatch(self, ctx, found):
 
     def fget_string(self, space):
         ctx = self.ctx
-        if isinstance(ctx, rsre_core.StrMatchContext):
-            return space.wrap(ctx._string)
+        if isinstance(ctx, rsre_core.BufMatchContext):
+            return space.wrap(ctx._buffer.as_str())
         elif isinstance(ctx, rsre_core.UnicodeMatchContext):
             return space.wrap(ctx._unicodestr)
         else:

pypy/module/cppyy/__init__.py

         '_template_byname'       : 'interp_cppyy.template_byname',
         '_std_string_name'       : 'interp_cppyy.std_string_name',
         '_set_class_generator'   : 'interp_cppyy.set_class_generator',
+        '_set_function_generator': 'interp_cppyy.set_function_generator',
         '_register_class'        : 'interp_cppyy.register_class',
         '_is_static'             : 'interp_cppyy.is_static',
+        '_get_nullptr'           : 'interp_cppyy.get_nullptr',
         'CPPInstance'            : 'interp_cppyy.W_CPPInstance',
         'addressof'              : 'interp_cppyy.addressof',
         'bind_object'            : 'interp_cppyy.bind_object',

pypy/module/cppyy/capi/__init__.py

File contents unchanged.

pypy/module/cppyy/capi/builtin_capi.py

     [C_SCOPE, C_INDEX], C_METHPTRGETTER_PTR,
     releasegil=ts_reflect,
     compilation_info=backend.eci,
-    elidable_function=True)
+    elidable_function=True,
+    random_effects_on_gcobjs=False)
 def c_get_methptr_getter(space, cppscope, index):
     return _c_get_methptr_getter(cppscope.handle, index)
 
     [], rffi.SIZE_T,
     releasegil=ts_memory,
     compilation_info=backend.eci,
-    elidable_function=True)
+    elidable_function=True,
+    random_effects_on_gcobjs=False)
 def c_function_arg_sizeof(space):
     return _c_function_arg_sizeof()
 _c_function_arg_typeoffset = rffi.llexternal(
     [], rffi.SIZE_T,
     releasegil=ts_memory,
     compilation_info=backend.eci,
-    elidable_function=True)
+    elidable_function=True,
+    random_effects_on_gcobjs=False)
 def c_function_arg_typeoffset(space):
     return _c_function_arg_typeoffset()
 
     [C_TYPE, C_TYPE], rffi.INT,
     releasegil=ts_reflect,
     compilation_info=backend.eci,
-    elidable_function=True)
+    elidable_function=True,
+    random_effects_on_gcobjs=False)
 @jit.elidable_promote('2')
 def c_is_subtype(space, derived, base):
     if derived == base:
     [C_TYPE, C_TYPE, C_OBJECT, rffi.INT], rffi.SIZE_T,
     releasegil=ts_reflect,
     compilation_info=backend.eci,
-    elidable_function=True)
+    elidable_function=True,
+    random_effects_on_gcobjs=False)
 @jit.elidable_promote('1,2,4')
 def c_base_offset(space, derived, base, address, direction):
     if derived == base:
     compilation_info=backend.eci)
 def c_stdstring2stdstring(space, cppobject):
     return _c_stdstring2stdstring(cppobject)
-_c_assign2stdstring = rffi.llexternal(
-    "cppyy_assign2stdstring",
-    [C_OBJECT, rffi.CCHARP], lltype.Void,
-    releasegil=ts_helper,
-    compilation_info=backend.eci)
-def c_assign2stdstring(space, cppobject, svalue):
-    charp = rffi.str2charp(svalue)
-    _c_assign2stdstring(cppobject, charp)
-    rffi.free_charp(charp)
-_c_free_stdstring = rffi.llexternal(
-    "cppyy_free_stdstring",
-    [C_OBJECT], lltype.Void,
-    releasegil=ts_helper,
-    compilation_info=backend.eci)
-def c_free_stdstring(space, cppobject):
-    _c_free_stdstring(cppobject)

pypy/module/cppyy/capi/capi_types.py

File contents unchanged.

pypy/module/cppyy/capi/cint_capi.py

 from pypy.interpreter.baseobjspace import W_Root
 
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
-from rpython.rtyper.lltypesystem import rffi
+from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib import libffi, rdynload
+from rpython.tool.udir import udir
+
+from pypy.module.cppyy.capi.capi_types import C_OBJECT
 
 
 __all__ = ['identify', 'std_string_name', 'eci', 'c_load_dictionary']
 if os.environ.get("ROOTSYS"):
     import commands
     (stat, incdir) = commands.getstatusoutput("root-config --incdir")
-    if stat != 0:        # presumably Reflex-only
-        rootincpath = [os.path.join(os.environ["ROOTSYS"], "include")]
+    if stat != 0:
+        rootincpath = [os.path.join(os.environ["ROOTSYS"], "include"), py.path.local(udir)]
         rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
     else:
-        rootincpath = [incdir]
+        rootincpath = [incdir, py.path.local(udir)]
         rootlibpath = commands.getoutput("root-config --libdir").split()
 else:
-    rootincpath = []
+    rootincpath = [py.path.local(udir)]
     rootlibpath = []
 
 def identify():
     return 'CINT'
 
-ts_reflect = False
-ts_call    = False
+ts_reflect = True
+ts_call    = True
 ts_memory  = False
 ts_helper  = False
 
     _cintdll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
 with rffi.scoped_str2charp('libCore.so') as ll_libname:
     _coredll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
+with rffi.scoped_str2charp('libHist.so') as ll_libname:
+    _coredll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
 
 eci = ExternalCompilationInfo(
     separate_module_files=[srcpath.join("cintcwrapper.cxx")],
     include_dirs=[incpath] + rootincpath,
     includes=["cintcwrapper.h"],
     library_dirs=rootlibpath,
-    libraries=["Core", "Cint"],
+    libraries=["Hist", "Core", "Cint"],
     use_cpp_linker=True,
 )
 
 
 
 # CINT-specific pythonizations ===============================================
+_c_charp2TString = rffi.llexternal(
+    "cppyy_charp2TString",
+    [rffi.CCHARP], C_OBJECT,
+    releasegil=ts_helper,
+    compilation_info=eci)
+def c_charp2TString(space, svalue):
+    charp = rffi.str2charp(svalue)
+    result = _c_charp2TString(charp)
+    rffi.free_charp(charp)
+    return result
+_c_TString2TString = rffi.llexternal(
+    "cppyy_TString2TString",
+    [C_OBJECT], C_OBJECT,
+    releasegil=ts_helper,
+    compilation_info=eci)
+def c_TString2TString(space, cppobject):
+    return _c_TString2TString(cppobject)
 
 def _get_string_data(space, w_obj, m1, m2 = None):
     from pypy.module.cppyy import interp_cppyy
         return w_1
     return obj.space.call_method(w_1, m2)
 
+### TF1 ----------------------------------------------------------------------
+class State(object):
+    def __init__(self, space):
+        self.tfn_pyfuncs = []
+        self.tfn_callbacks = []
+
+_create_tf1 = rffi.llexternal(
+    "cppyy_create_tf1",
+    [rffi.CCHARP, rffi.ULONG, rffi.DOUBLE, rffi.DOUBLE, rffi.INT], C_OBJECT,
+    releasegil=False,
+    compilation_info=eci)
+
+@unwrap_spec(args_w='args_w')
+def tf1_tf1(space, w_self, args_w):
+    """Pythonized version of TF1 constructor:
+    takes functions and callable objects, and allows a callback into them."""
+
+    from pypy.module.cppyy import interp_cppyy
+    tf1_class = interp_cppyy.scope_byname(space, "TF1")
+
+    # expected signature:
+    #  1. (char* name, pyfunc, double xmin, double xmax, int npar = 0)
+    argc = len(args_w)
+
+    try:
+        # Note: argcount is +1 for the class (== w_self)
+        if argc < 5 or 6 < argc:
+            raise TypeError("wrong number of arguments")
+
+        # second argument must be a name
+        funcname = space.str_w(args_w[1])
+
+        # last (optional) argument is number of parameters
+        npar = 0
+        if argc == 6: npar = space.int_w(args_w[5])
+
+        # third argument must be a callable python object
+        w_callable = args_w[2]
+        if not space.is_true(space.callable(w_callable)):
+            raise TypeError("2nd argument is not a valid python callable")
+
+        # generate a pointer to function
+        from pypy.module._cffi_backend import newtype, ctypefunc, func
+
+        c_double  = newtype.new_primitive_type(space, 'double')
+        c_doublep = newtype.new_pointer_type(space, c_double)
+
+        # wrap the callable as the signature needs modifying
+        w_ifunc = interp_cppyy.get_interface_func(space, w_callable, npar)
+
+        w_cfunc = ctypefunc.W_CTypeFunc(space, [c_doublep, c_doublep], c_double, False)
+        w_callback = func.callback(space, w_cfunc, w_ifunc, None)
+        funcaddr = rffi.cast(rffi.ULONG, w_callback.get_closure())
+
+        # so far, so good; leaves on issue: CINT is expecting a wrapper, but
+        # we need the overload that takes a function pointer, which is not in
+        # the dictionary, hence this helper:
+        newinst = _create_tf1(space.str_w(args_w[1]), funcaddr,
+                      space.float_w(args_w[3]), space.float_w(args_w[4]), npar)
+ 
+        from pypy.module.cppyy import interp_cppyy
+        w_instance = interp_cppyy.wrap_cppobject(space, newinst, tf1_class,
+                                      do_cast=False, python_owns=True, fresh=True)
+
+        # tie all the life times to the TF1 instance
+        space.setattr(w_instance, space.wrap('_callback'), w_callback)
+
+        return w_instance
+    except (OperationError, TypeError, IndexError), e:
+        newargs_w = args_w[1:]     # drop class
+
+    # return control back to the original, unpythonized overload
+    ol = tf1_class.get_overload("TF1")
+    return ol.call(None, newargs_w)
+
 ### TTree --------------------------------------------------------------------
 _ttree_Branch = rffi.llexternal(
     "cppyy_ttree_Branch",
-    [rffi.VOIDP, rffi.CCHARP, rffi.CCHARP, rffi.VOIDP, rffi.INT, rffi.INT], rffi.LONG,
+    [rffi.VOIDP, rffi.CCHARP, rffi.CCHARP, rffi.VOIDP, rffi.INT, rffi.INT], C_OBJECT,
     releasegil=False,
     compilation_info=eci)
 
         # some instance
         klass = interp_cppyy.scope_byname(space, space.str_w(w_klassname))
         w_obj = klass.construct()
+        # 0x10000 = kDeleteObject; reset because we own the object
+        space.call_method(w_branch, "ResetBit", space.wrap(0x10000))
         space.call_method(w_branch, "SetObject", w_obj)
         space.call_method(w_branch, "GetEntry", space.wrap(entry))
         space.setattr(w_self, args_w[0], w_obj)
 
     allfuncs = [
 
+        ### TF1
+        tf1_tf1,
+
         ### TTree
         ttree_Branch, ttree_iter, ttree_getattr,
     ]
 # callback coming in when app-level bound classes have been created
 def pythonize(space, name, w_pycppclass):
 
-    if name == "TFile":
+    if name == "TCollection":
+        _method_alias(space, w_pycppclass, "append", "Add")
+        _method_alias(space, w_pycppclass, "__len__", "GetSize")
+
+    elif name == "TF1":
+        space.setattr(w_pycppclass, space.wrap("__new__"), _pythonizations["tf1_tf1"])
+
+    elif name == "TFile":
         _method_alias(space, w_pycppclass, "__getattr__", "Get")
 
     elif name == "TObjString":
 
     elif name[0:8] == "TVectorT":    # TVectorT<> template
         _method_alias(space, w_pycppclass, "__len__", "GetNoElements")
+
+# destruction callback (needs better solution, but this is for CINT
+# only and should not appear outside of ROOT-specific uses)
+from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL
+
+@cpython_api([rffi.VOIDP], lltype.Void, error=CANNOT_FAIL)
+def _Py_cppyy_recursive_remove(space, cppobject):
+    from pypy.module.cppyy.interp_cppyy import memory_regulator
+    from pypy.module.cppyy.capi import C_OBJECT, C_NULL_OBJECT
+
+    obj = memory_regulator.retrieve(rffi.cast(C_OBJECT, cppobject))
+    if obj is not None:
+        memory_regulator.unregister(obj)
+        obj._rawobject = C_NULL_OBJECT

pypy/module/cppyy/capi/cling_capi.py

+import py, os
+
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+from rpython.rtyper.lltypesystem import rffi
+from rpython.rlib import libffi, rdynload
+
+__all__ = ['identify', 'std_string_name', 'eci', 'c_load_dictionary']
+
+pkgpath = py.path.local(__file__).dirpath().join(os.pardir)
+srcpath = pkgpath.join("src")
+incpath = pkgpath.join("include")
+
+import commands
+(config_stat, incdir) = commands.getstatusoutput("root-config --incdir")
+
+if os.environ.get("ROOTSYS"):
+    if config_stat != 0:     # presumably Reflex-only
+        rootincpath = [os.path.join(os.environ["ROOTSYS"], "interpreter/cling/include"),
+                       os.path.join(os.environ["ROOTSYS"], "interpreter/llvm/inst/include")]
+        rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
+    else:
+        rootincpath = [incdir]
+        rootlibpath = commands.getoutput("root-config --libdir").split()
+else:
+    if config_stat == 0:
+        rootincpath = [incdir]
+        rootlibpath = commands.getoutput("root-config --libdir").split()
+    else:
+        rootincpath = []
+        rootlibpath = []
+
+def identify():
+    return 'Cling'
+
+ts_reflect = False
+ts_call    = 'auto'
+ts_memory  = 'auto'
+ts_helper  = 'auto'
+
+std_string_name = 'std::basic_string<char>'
+
+eci = ExternalCompilationInfo(
+    separate_module_files=[srcpath.join("clingcwrapper.cxx")],
+    include_dirs=[incpath] + rootincpath,
+    includes=["clingcwrapper.h"],
+    library_dirs=rootlibpath,
+    libraries=["Cling"],
+    compile_extra=["-fno-strict-aliasing"],
+    use_cpp_linker=True,
+)
+
+_c_load_dictionary = rffi.llexternal(
+    "cppyy_load_dictionary",
+    [rffi.CCHARP], rdynload.DLLHANDLE,
+    releasegil=False,
+    compilation_info=eci)
+
+def c_load_dictionary(name):
+    pch = _c_load_dictionary(name)
+    return pch
+
+
+# Cling-specific pythonizations
+def register_pythonizations(space):
+    "NOT_RPYTHON"
+    pass
+
+def pythonize(space, name, w_pycppclass):
+    pass

pypy/module/cppyy/capi/loadable_capi.py

 
             'charp2stdstring'          : ([c_ccharp],                 c_object),
             'stdstring2stdstring'      : ([c_object],                 c_object),
-            'assign2stdstring'         : ([c_object, c_ccharp],       c_void),
-            'free_stdstring'           : ([c_object],                 c_void),
         }
 
+        # size/offset are backend-specific but fixed after load
+        self.c_sizeof_farg = 0
+        self.c_offset_farg = 0
+
+
 def load_reflection_library(space):
     state = space.fromcache(State)
     if state.library is None:
         from pypy.module._cffi_backend.libraryobj import W_Library
         state.library = W_Library(space, reflection_library, rdynload.RTLD_LOCAL | rdynload.RTLD_LAZY)
+        if state.library:
+            # fix constants
+            state.c_sizeof_farg = _cdata_to_size_t(space, call_capi(space, 'function_arg_sizeof', []))
+            state.c_offset_farg = _cdata_to_size_t(space, call_capi(space, 'function_arg_typeoffset', []))
     return state.library
 
 def verify_backend(space):
     return _cdata_to_ptr(space, call_capi(space, 'allocate_function_args', [_Arg(l=size)]))
 def c_deallocate_function_args(space, cargs):
     call_capi(space, 'deallocate_function_args', [_Arg(vp=cargs)])
-@jit.elidable
 def c_function_arg_sizeof(space):
-    return _cdata_to_size_t(space, call_capi(space, 'function_arg_sizeof', []))
-@jit.elidable
+    state = space.fromcache(State)
+    return state.c_sizeof_farg
 def c_function_arg_typeoffset(space):
-    return _cdata_to_size_t(space, call_capi(space, 'function_arg_typeoffset', []))
+    state = space.fromcache(State)
+    return state.c_offset_farg
 
 # scope reflection information -----------------------------------------------
 def c_is_namespace(space, scope):
 def c_base_name(space, cppclass, base_index):
     args = [_Arg(l=cppclass.handle), _Arg(l=base_index)]
     return charp2str_free(space, call_capi(space, 'base_name', args))
-@jit.elidable_promote('2')
 def c_is_subtype(space, derived, base):
+    jit.promote(base)
     if derived == base:
         return bool(1)
     return space.bool_w(call_capi(space, 'is_subtype', [_Arg(l=derived.handle), _Arg(l=base.handle)]))
 
-@jit.elidable_promote('1,2,4')
 def _c_base_offset(space, derived_h, base_h, address, direction):
     args = [_Arg(l=derived_h), _Arg(l=base_h), _Arg(l=address), _Arg(l=direction)]
     return _cdata_to_size_t(space, call_capi(space, 'base_offset', args))
     return _cdata_to_cobject(space, call_capi(space, 'charp2stdstring', [_Arg(s=svalue)]))
 def c_stdstring2stdstring(space, cppobject):
     return _cdata_to_cobject(space, call_capi(space, 'stdstring2stdstring', [_Arg(l=cppobject)]))
-def c_assign2stdstring(space, cppobject, svalue):
-    args = [_Arg(l=cppobject), _Arg(s=svalue)]
-    call_capi(space, 'assign2stdstring', args)
-def c_free_stdstring(space, cppobject):
-    call_capi(space, 'free_stdstring', [_Arg(l=cppobject)])
 
 # loadable-capi-specific pythonizations (none, as the capi isn't known until runtime)
 def register_pythonizations(space):

pypy/module/cppyy/converter.py

 from rpython.rlib.rarithmetic import r_singlefloat
 from rpython.rlib import jit_libffi, rfloat
 
-from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
-from pypy.module._rawffi.array import W_Array
+from pypy.module._rawffi.interp_rawffi import letter2tp
+from pypy.module._rawffi.array import W_Array, W_ArrayInstance
 
 from pypy.module.cppyy import helper, capi, ffitypes
 
         return rawobject
     return capi.C_NULL_OBJECT
 
+def is_nullpointer_specialcase(space, w_obj):
+    # 0, None, and nullptr may serve as "NULL", check for any of them
+
+    # integer 0
+    try:
+        return space.int_w(w_obj) == 0
+    except Exception:
+        pass
+    # None or nullptr
+    from pypy.module.cppyy import interp_cppyy
+    return space.is_true(space.is_(w_obj, space.w_None)) or \
+        space.is_true(space.is_(w_obj, interp_cppyy.get_nullptr(space)))
+
 def get_rawbuffer(space, w_obj):
+    # raw buffer
     try:
         buf = space.buffer_w(w_obj, space.BUF_SIMPLE)
         return rffi.cast(rffi.VOIDP, buf.get_raw_address())
     except Exception:
         pass
-    # special case: allow integer 0 as NULL
+    # array type
     try:
-        buf = space.int_w(w_obj)
-        if buf == 0:
-            return rffi.cast(rffi.VOIDP, 0)
+        arr = space.interp_w(W_ArrayInstance, w_obj, can_be_None=True)
+        if arr:
+            return rffi.cast(rffi.VOIDP, space.uint_w(arr.getbuffer(space)))
     except Exception:
         pass
-    # special case: allow None as NULL
-    if space.is_true(space.is_(w_obj, space.w_None)):
+    # pre-defined NULL
+    if is_nullpointer_specialcase(space, w_obj):
         return rffi.cast(rffi.VOIDP, 0)
     raise TypeError("not an addressable buffer")
 
     def __getattr__(self, name):
         if name.startswith('array_'):
             typecode = name[len('array_'):]
-            arr = self.space.interp_w(W_Array, unpack_simple_shape(self.space, self.space.wrap(typecode)))
+            arr = self.space.interp_w(W_Array, letter2tp(self.space, typecode))
             setattr(self, name, arr)
             return arr
         raise AttributeError(name)
             self.size = array_size
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
-        if hasattr(space, "fake"):
-            raise NotImplementedError
         # read access, so no copy needed
         address_value = self._get_raw_address(space, w_obj, offset)
         address = rffi.cast(rffi.ULONG, address_value)
         self.name = name
 
     def convert_argument(self, space, w_obj, address, call_local):
-        raise OperationError(space.w_TypeError,
-                             space.wrap('no converter available for type "%s"' % self.name))
+        self._is_abstract(space)
 
 
 class BoolConverter(ffitypes.typeid(bool), TypeConverter):
         try:
             obj = get_rawbuffer(space, w_obj)
         except TypeError:
-            obj = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+            try:
+                # TODO: accept a 'capsule' rather than naked int
+                # (do accept int(0), though)
+                obj = rffi.cast(rffi.VOIDP, space.int_w(w_obj))
+            except Exception:
+                obj = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
         return obj
 
     def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = self._unwrap_object(space, w_obj)
 
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        # returned as a long value for the address (INTPTR_T is not proper
+        # per se, but rffi does not come with a PTRDIFF_T)
+        address = self._get_raw_address(space, w_obj, offset)
+        ptrval = rffi.cast(rffi.ULONG, rffi.cast(rffi.VOIDPP, address)[0])
+        if ptrval == 0:
+            from pypy.module.cppyy import interp_cppyy
+            return interp_cppyy.get_nullptr(space)
+        arr = space.interp_w(W_Array, letter2tp(space, 'P'))
+        return arr.fromaddress(space, ptrval, sys.maxint)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset))
+        if is_nullpointer_specialcase(space, w_value):
+            address[0] = rffi.cast(rffi.VOIDP, 0)
+        else:
+            address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
+
 class VoidPtrPtrConverter(TypeConverter):
     _immutable_fields_ = ['uses_local']
 
     _immutable_fields_ = ['uses_local']
     uses_local = True
 
-class InstancePtrConverter(TypeConverter):
+class InstanceRefConverter(TypeConverter):
     _immutable_fields_ = ['libffitype', 'cppclass']
 
     libffitype  = jit_libffi.types.pointer
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
 
-    def from_memory(self, space, w_obj, w_pycppclass, offset):
-        address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
-        from pypy.module.cppyy import interp_cppyy
-        return interp_cppyy.wrap_cppobject(space, address, self.cppclass,
-                                           do_cast=False, is_ref=True)
-
-    def to_memory(self, space, w_obj, w_value, offset):
-        address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset))
-        address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
-
-class InstanceConverter(InstancePtrConverter):
+class InstanceConverter(InstanceRefConverter):
 
     def convert_argument_libffi(self, space, w_obj, address, call_local):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
     def to_memory(self, space, w_obj, w_value, offset):
         self._is_abstract(space)
 
+
+class InstancePtrConverter(InstanceRefConverter):
+
+    def _unwrap_object(self, space, w_obj):
+        try:
+            return InstanceRefConverter._unwrap_object(self, space, w_obj)
+        except OperationError, e:
+            # if not instance, allow certain special cases
+            if is_nullpointer_specialcase(space, w_obj):
+                return capi.C_NULL_OBJECT
+            raise e
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
+        from pypy.module.cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppobject(space, address, self.cppclass,
+                                           do_cast=False, is_ref=True)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset))
+        address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
+
 class InstancePtrPtrConverter(InstancePtrConverter):
     _immutable_fields_ = ['uses_local']
 
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
-    def from_memory(self, space, w_obj, w_pycppclass, offset):
-        self._is_abstract(space)
-
-    def to_memory(self, space, w_obj, w_value, offset):
-        self._is_abstract(space)
-
     def finalize_call(self, space, w_obj, call_local):
         from pypy.module.cppyy.interp_cppyy import W_CPPInstance
         assert isinstance(w_obj, W_CPPInstance)
 
 
 class StdStringConverter(InstanceConverter):
-    _immutable_fields_ = ['cppclass']
 
     def __init__(self, space, extra):
         from pypy.module.cppyy import interp_cppyy
         InstanceConverter.__init__(self, space, cppclass)
 
     def _unwrap_object(self, space, w_obj):
-        try:
+        from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+        if isinstance(w_obj, W_CPPInstance):
+            arg = InstanceConverter._unwrap_object(self, space, w_obj)
+            return capi.c_stdstring2stdstring(space, arg)
+        else:
             return capi.c_charp2stdstring(space, space.str_w(w_obj))
-        except Exception, e:
-            arg = InstanceConverter._unwrap_object(self, space, w_obj)
-            result = capi.c_stdstring2stdstring(space, arg)
-            return result
 
     def to_memory(self, space, w_obj, w_value, offset):
         try:
             address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
-            capi.c_assign2stdstring(space, address, space.str_w(w_value))
-            return
+            assign = self.cppclass.get_overload("__assign__")
+            from pypy.module.cppyy import interp_cppyy
+            assign.call(
+                interp_cppyy.wrap_cppobject(space, address, self.cppclass, do_cast=False), [w_value])
         except Exception:
-            pass
-        return InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
+            InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
 
     def free_argument(self, space, arg, call_local):
-        capi.c_free_stdstring(space, rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
+        capi.c_destruct(space, self.cppclass, rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
 
 class StdStringRefConverter(InstancePtrConverter):
     _immutable_fields_ = ['cppclass']
     def free_argument(self, space, arg, call_local):
         if hasattr(space, "fake"):
             raise NotImplementedError
+        space.getbuiltinmodule("cpyext")
         from pypy.module.cpyext.pyobject import Py_DecRef, PyObject
         Py_DecRef(space, rffi.cast(PyObject, rffi.cast(rffi.VOIDPP, arg)[0]))
 
         # type check for the benefit of the annotator
         from pypy.module.cppyy.interp_cppyy import W_CPPClass
         cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
-        if compound == "*" or compound == "&":
+        if compound == "*":
             return InstancePtrConverter(space, cppclass)
+        elif compound == "&":
+            return InstanceRefConverter(space, cppclass)
         elif compound == "**":
             return InstancePtrPtrConverter(space, cppclass)
         elif compound == "":
 _converters["void**"]                   = VoidPtrPtrConverter
 _converters["void*&"]                   = VoidPtrRefConverter
 
-# special cases (note: CINT backend requires the simple name 'string')
+# special cases (note: 'string' aliases added below)
 _converters["std::basic_string<char>"]           = StdStringConverter
 _converters["const std::basic_string<char>&"]    = StdStringConverter     # TODO: shouldn't copy
 _converters["std::basic_string<char>&"]          = StdStringRefConverter
     for c_type, alias in aliases:
         _converters[alias] = _converters[c_type]
 _add_aliased_converters()
+
+# ROOT-specific converters (TODO: this is a general use case and should grow
+# an API; putting it here is done only to circumvent circular imports)
+if capi.identify() == "CINT":
+
+    class TStringConverter(InstanceConverter):
+        def __init__(self, space, extra):
+            from pypy.module.cppyy import interp_cppyy
+            cppclass = interp_cppyy.scope_byname(space, "TString")
+            InstanceConverter.__init__(self, space, cppclass)
+
+        def _unwrap_object(self, space, w_obj):
+            from pypy.module.cppyy import interp_cppyy
+            if isinstance(w_obj, interp_cppyy.W_CPPInstance):
+                arg = InstanceConverter._unwrap_object(self, space, w_obj)
+                return capi.backend.c_TString2TString(space, arg)
+            else:
+                return capi.backend.c_charp2TString(space, space.str_w(w_obj))
+
+        def free_argument(self, space, arg, call_local):
+            capi.c_destruct(space, self.cppclass, rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
+
+    _converters["TString"]        = TStringConverter
+    _converters["const TString&"] = TStringConverter

pypy/module/cppyy/executor.py

         if hasattr(space, "fake"):
             raise NotImplementedError
         lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
-        address = rffi.cast(rffi.ULONG, lresult)
+        ptrval = 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)
+        if ptrval == 0:
+            from pypy.module.cppyy import interp_cppyy
+            return interp_cppyy.get_nullptr(space)
+        return arr.fromaddress(space, ptrval, sys.maxint)
 
 
 class VoidExecutor(FunctionExecutor):
         from pypy.module.cppyy import interp_cppyy
         newthis = capi.c_constructor(space, cppmethod, cpptype, num_args, args)
         assert lltype.typeOf(newthis) == capi.C_OBJECT
-        return space.wrap(newthis)
+        return space.wrap(rffi.cast(rffi.LONG, newthis))   # really want ptrdiff_t here
 
 
 class InstancePtrExecutor(FunctionExecutor):
         from pypy.module.cppyy import interp_cppyy
         long_result = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
         ptr_result = rffi.cast(capi.C_OBJECT, long_result)
-        return interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass)
+        pyres = interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass)
+        return pyres
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
         long_result = capi.c_call_o(space, cppmethod, cppthis, num_args, args, self.cppclass)
         ptr_result = rffi.cast(capi.C_OBJECT, long_result)
         return interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass,
-                                           do_cast=False, python_owns=True)
+                                           do_cast=False, python_owns=True, fresh=True)
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
+class StdStringRefExecutor(InstancePtrExecutor):
+
+    def __init__(self, space, cppclass):
+        from pypy.module.cppyy import interp_cppyy
+        cppclass = interp_cppyy.scope_byname(space, capi.std_string_name)
+        InstancePtrExecutor.__init__(self, space, cppclass)
+
 
 class PyObjectExecutor(PtrTypeExecutor):
 
 _executors["void*"]               = PtrTypeExecutor
 _executors["const char*"]         = CStringExecutor
 
-# special cases
+# special cases (note: 'string' aliases added below)
 _executors["constructor"]         = ConstructorExecutor
 
 _executors["std::basic_string<char>"]         = StdStringExecutor
-_executors["const std::basic_string<char>&"]  = StdStringExecutor
-_executors["std::basic_string<char>&"]        = StdStringExecutor    # TODO: shouldn't copy
+_executors["const std::basic_string<char>&"]  = StdStringRefExecutor
+_executors["std::basic_string<char>&"]        = StdStringRefExecutor
 
 _executors["PyObject*"]           = PyObjectExecutor
 
     "NOT_RPYTHON"
     aliases = (
         ("const char*",                     "char*"),
+
         ("std::basic_string<char>",         "string"),
+        ("const std::basic_string<char>&",  "const string&"),
+        ("std::basic_string<char>&",        "string&"),
+
         ("PyObject*",                       "_object*"),
     )
 

pypy/module/cppyy/include/capi.h

     cppyy_index_t cppyy_get_global_operator(
         cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op);
 
-    /* method properties -----------------------------------------------------  */
+    /* method properties ------------------------------------------------------ */
     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 ------------------------------------  */
+    /* data member reflection information ------------------------------------- */
     int cppyy_num_datamembers(cppyy_scope_t scope);
     char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index);
     char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index);
 
     int cppyy_datamember_index(cppyy_scope_t scope, const char* name);
 
-    /* data member properties ------------------------------------------------  */
+    /* data member properties ------------------------------------------------- */
     int cppyy_is_publicdata(cppyy_type_t type, int datamember_index);
     int cppyy_is_staticdata(cppyy_type_t type, int datamember_index);
 
 
     cppyy_object_t cppyy_charp2stdstring(const char* str);
     cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr);
-    void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str);
-    void cppyy_free_stdstring(cppyy_object_t ptr);
 
 #ifdef __cplusplus
 }

pypy/module/cppyy/include/cintcwrapper.h

     void* cppyy_load_dictionary(const char* lib_name);
 
     /* pythonization helpers */
+    cppyy_object_t cppyy_create_tf1(const char* funcname, unsigned long address,
+        double xmin, double xmax, int npar);
+
     cppyy_object_t cppyy_ttree_Branch(
         void* vtree, const char* branchname, const char* classname,
         void* addobj, int bufsize, int splitlevel);
 
     long long cppyy_ttree_GetEntry(void* vtree, long long entry);
 
+    cppyy_object_t cppyy_charp2TString(const char* str);
+    cppyy_object_t cppyy_TString2TString(cppyy_object_t ptr);
+
 #ifdef __cplusplus
 }
 #endif // ifdef __cplusplus

pypy/module/cppyy/include/clingcwrapper.h

+#ifndef CPPYY_CLINGCWRAPPER
+#define CPPYY_CLINGCWRAPPER
+
+#include "capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // ifdef __cplusplus
+
+    /* misc helpers */
+    void* cppyy_load_dictionary(const char* lib_name);
+
+#ifdef __cplusplus
+}
+#endif // ifdef __cplusplus
+
+// TODO: pick up from llvm-config --cxxflags
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+
+// Wrapper callback: except this to become available from Cling directly
+typedef void (*CPPYY_Cling_Wrapper_t)(void*, int, void**, void*);
+
+#endif // ifndef CPPYY_CLINGCWRAPPER

pypy/module/cppyy/include/cppyy.h

 #ifdef __cplusplus
 struct CPPYY_G__p2p {
 #else
-#typedef struct
+typedef struct {
 #endif
   long i;
   int reftype;

pypy/module/cppyy/interp_cppyy.py

     def __init__(self, space):
         self.cppscope_cache = {
             "void" : W_CPPClass(space, "void", capi.C_NULL_TYPE) }
+        self.w_nullptr = None
         self.cpptemplate_cache = {}
         self.cppclass_registry = {}
         self.w_clgen_callback = None
+        self.w_fngen_callback = None
+
+def get_nullptr(space):
+    if hasattr(space, "fake"):
+        raise NotImplementedError
+    state = space.fromcache(State)
+    if state.w_nullptr is None:
+        from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+        from pypy.module._rawffi.array import W_Array, W_ArrayInstance
+        arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap('P')))
+        # 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, rffi.cast(rffi.ULONG, 0), 0)
+        assert isinstance(nullarr, W_ArrayInstance)
+        nullarr.free(space)
+        state.w_nullptr = space.wrap(nullarr)
+    return state.w_nullptr
 
 @unwrap_spec(name=str)
 def resolve_name(space, name):
     state = space.fromcache(State)
     state.w_clgen_callback = w_callback
 
+@unwrap_spec(w_callback=W_Root)
+def set_function_generator(space, w_callback):
+    state = space.fromcache(State)
+    state.w_fngen_callback = w_callback
+
 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)
     # class allows simple aliasing of methods)
     capi.pythonize(space, cppclass.name, w_pycppclass)
     state = space.fromcache(State)
-    state.cppclass_registry[cppclass.handle] = w_pycppclass
+    state.cppclass_registry[rffi.cast(rffi.LONG, cppclass.handle)] = w_pycppclass
 
 
 class W_CPPLibrary(W_Root):
     def get_returntype(self):
         return self.space.wrap(self.converter.name)
 
-    @jit.elidable_promote()
     def _get_offset(self, cppinstance):
         if cppinstance:
             assert lltype.typeOf(cppinstance.cppclass.handle) == lltype.typeOf(self.scope.handle)
-            offset = self.offset + capi.c_base_offset(self.space,
-                cppinstance.cppclass, self.scope, cppinstance.get_rawobject(), 1)
+            offset = self.offset + cppinstance.cppclass.get_base_offset(cppinstance, self.scope)
         else:
             offset = self.offset
         return offset
     def get_method_names(self):
         return self.space.newlist([self.space.wrap(name) for name in self.methods])
 
-    @jit.elidable_promote('0')
     def get_overload(self, name):
         try:
             return self.methods[name]
     def get_datamember_names(self):
         return self.space.newlist([self.space.wrap(name) for name in self.datamembers])
 
-    @jit.elidable_promote('0')
     def get_datamember(self, name):
         try:
             return self.datamembers[name]
         self.datamembers[name] = new_dm
         return new_dm
 
-    @jit.elidable_promote('0')
     def dispatch(self, name, signature):
         overload = self.get_overload(name)
         sig = '(%s)' % signature
     def find_datamember(self, name):
         raise self.missing_attribute_error(name)
 
+    def get_base_offset(self, cppinstance, calling_scope):
+        assert self == cppinstance.cppclass
+        return 0
+
     def get_cppthis(self, cppinstance, calling_scope):
         assert self == cppinstance.cppclass
         return cppinstance.get_rawobject()
 
 class W_ComplexCPPClass(W_CPPClass):
 
-    def get_cppthis(self, cppinstance, calling_scope):
+    def get_base_offset(self, cppinstance, calling_scope):
         assert self == cppinstance.cppclass
         offset = capi.c_base_offset(self.space,
                                     self, calling_scope, cppinstance.get_rawobject(), 1)
+        return offset
+
+    def get_cppthis(self, cppinstance, calling_scope):
+        assert self == cppinstance.cppclass
+        offset = self.get_base_offset(cppinstance, calling_scope)
         return capi.direct_ptradd(cppinstance.get_rawobject(), offset)
 
 W_ComplexCPPClass.typedef = TypeDef(
 def get_pythonized_cppclass(space, handle):
     state = space.fromcache(State)
     try:
-        w_pycppclass = state.cppclass_registry[handle]
+        w_pycppclass = state.cppclass_registry[rffi.cast(rffi.LONG, handle)]
     except KeyError:
         final_name = capi.c_scoped_final_name(space, 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 get_interface_func(space, w_callable, npar):
+    state = space.fromcache(State)
+    return space.call_function(state.w_fngen_callback, w_callable, space.wrap(npar))
+
 def wrap_cppobject(space, rawobject, cppclass,
                    do_cast=True, python_owns=False, is_ref=False, fresh=False):
     rawobject = rffi.cast(capi.C_OBJECT, rawobject)
 
-    # cast to actual cast if requested and possible
-    w_pycppclass = space.w_None
+    # cast to actual if requested and possible
+    w_pycppclass = None
     if do_cast and rawobject:
         actual = capi.c_actual_class(space, cppclass, rawobject)
         if actual != cppclass.handle:
                 # the variables are re-assigned yet)
                 pass
 
-    if space.is_w(w_pycppclass, space.w_None):
+    if w_pycppclass is None:
         w_pycppclass = get_pythonized_cppclass(space, cppclass.handle)
 
     # try to recycle existing object if this one is not newly created
     memory_regulator.register(cppinstance)
     return w_cppinstance
 
-@unwrap_spec(w_cppinstance=W_CPPInstance)
-def addressof(space, w_cppinstance):
-    """Takes a bound C++ instance, returns the raw address."""
-    address = rffi.cast(rffi.LONG, w_cppinstance.get_rawobject())
+def _addressof(space, w_obj):
+    try:
+        # attempt to extract address from array
+        return rffi.cast(rffi.INTPTR_T, converter.get_rawbuffer(space, w_obj))
+    except TypeError:
+        pass
+    # attempt to get address of C++ instance
+    return rffi.cast(rffi.INTPTR_T, converter.get_rawobject(space, w_obj))
+
+@unwrap_spec(w_obj=W_Root)
+def addressof(space, w_obj):
+    """Takes a bound C++ instance or array, returns the raw address."""
+    address = _addressof(space, w_obj)
     return space.wrap(address)
 
-@unwrap_spec(address=int, owns=bool)
-def bind_object(space, address, w_pycppclass, owns=False):
+@unwrap_spec(owns=bool, cast=bool)
+def bind_object(space, w_obj, w_pycppclass, owns=False, cast=False):
     """Takes an address and a bound C++ class proxy, returns a bound instance."""
-    rawobject = rffi.cast(capi.C_OBJECT, address)
+    try:
+        # attempt address from array or C++ instance
+        rawobject = rffi.cast(capi.C_OBJECT, _addressof(space, w_obj))
+    except Exception:
+        # accept integer value as address
+        rawobject = rffi.cast(capi.C_OBJECT, space.uint_w(w_obj))
     w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
     if not w_cppclass:
         w_cppclass = scope_byname(space, space.str_w(w_pycppclass))
             raise OperationError(space.w_TypeError,
                 space.wrap("no such class: %s" % space.str_w(w_pycppclass)))
     cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
-    return wrap_cppobject(space, rawobject, cppclass, do_cast=False, python_owns=owns)
+    return wrap_cppobject(space, rawobject, cppclass, do_cast=cast, python_owns=owns)

pypy/module/cppyy/pythonify.py

 def clgen_callback(name):
     return get_pycppclass(name)
 
+def fngen_callback(func, npar): # todo, some kind of arg transform spec
+    if npar == 0:
+        def wrapper(a0, a1):
+            la0 = [a0[0], a0[1], a0[2], a0[3]]
+            return func(la0)
+        return wrapper
+    else:
+        def wrapper(a0, a1):
+            la0 = [a0[0], a0[1], a0[2], a0[3]]
+            la1 = [a1[i] for i in range(npar)]
+            return func(la0, la1)
+        return wrapper
+
 
 def make_static_function(func_name, cppol):
     def function(*args):
     # class generator callback
     cppyy._set_class_generator(clgen_callback)
 
+    # function generator callback
+    cppyy._set_function_generator(fngen_callback)
+
     # 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)
     # be the same issue for all typedef'd builtin types
     setattr(gbl, 'unsigned int', int)
 
+    # install nullptr as a unique reference
+    setattr(gbl, 'nullptr', cppyy._get_nullptr())
+
     # install for user access
     cppyy.gbl = gbl
 

pypy/module/cppyy/src/cintcwrapper.cxx

 
 #include "TApplication.h"
 #include "TInterpreter.h"
+#include "TVirtualMutex.h"
 #include "Getline.h"
 
 #include "TBaseClass.h"
 // for pythonization
 #include "TTree.h"
 #include "TBranch.h"
+#include "TF1.h"
+#include "TString.h"
 
 #include "Api.h"
 
 #include <string>
 #include <utility>
 
+// for recursive_remove callback
+#include "pypy_macros.h"
+
 
 /* ROOT/CINT internals --------------------------------------------------- */
 extern long G__store_struct_offset;
 extern "C" void G__LockCriticalSection();
 extern "C" void G__UnlockCriticalSection();
 
-#define G__SETMEMFUNCENV      (long)0x7fff0035
-#define G__NOP                (long)0x7fff00ff
-
 namespace {
 
 class Cppyy_OpenedTClass : public TDictionary {
     TList*             fAllPubMethod;   //all public methods (including from base classes)
 };
 
+// memory regulation (cppyy_recursive_remove is generated as a cpyext capi call)
+extern "C" void _Py_cppyy_recursive_remove(void*);
+
+class Cppyy_MemoryRegulator : public TObject {
+public:
+    virtual void RecursiveRemove(TObject* object) {
+        _Py_cppyy_recursive_remove((void*)object);
+    }
+};
+
 } // unnamed namespace
 
 
 /* initialization of the ROOT system (debatable ... ) --------------------- */
 namespace {
 
+static Cppyy_MemoryRegulator s_memreg;
+
 class TCppyyApplication : public TApplication {
 public:
     TCppyyApplication(const char* acn, Int_t* argc, char** argv, Bool_t do_load = kTRUE)
 
         // enable auto-loader
         gInterpreter->EnableAutoLoading();
+
+        // enable memory regulation
+        gROOT->GetListOfCleanups()->Add(&s_memreg);
     }
 };
 
-static const char* appname = "pypy-cppyy";
+static const char* appname = "PyPyROOT";
 
 class ApplicationStarter {
 public:
         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.
- 
+        // CINT ignores std/::std, so point them to the global namespace
+        g_classref_indices["std"]   = (ClassRefs_t::size_type)GLOBAL_HANDLE;
+        g_classref_indices["::std"] = (ClassRefs_t::size_type)GLOBAL_HANDLE;
+
         // an offset for the interpreted methods
         g_interpreted.push_back(G__MethodInfo());
 
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass())
         return (TFunction*)cr->GetListOfMethods()->At(idx);
+    assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
     return (TFunction*)idx;
 }
 
 
 /* name to opaque C++ scope representation -------------------------------- */
 int cppyy_num_scopes(cppyy_scope_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         /* not supported as CINT does not store classes hierarchically */
         return 0;
     }
+    assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
     return gClassTable->Classes();
 }
 
 char* cppyy_scope_name(cppyy_scope_t handle, int iscope) {
+    R__LOCKGUARD2(gCINTMutex);
     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;
     }
+    assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
     std::string name = gClassTable->At(iscope);
     if (name.find("::") == std::string::npos)
         return cppstring_to_cstring(name);
 }
 
 char* cppyy_resolve_name(const char* cppitem_name) {
+    R__LOCKGUARD2(gCINTMutex);
     std::string tname = cppitem_name;
 
     // global namespace?
     if (ti.Property() & G__BIT_ISENUM)
         return cppstring_to_cstring("unsigned int");
 
-    // actual typedef resolution; add back array declartion portion, if needed
+    // actual typedef resolution; add back array declaration portion, if needed
     std::string rt = ti.TrueName();
 
     // builtin STL types have fake typedefs :/
 }
 
 cppyy_scope_t cppyy_get_scope(const char* scope_name) {
+    R__LOCKGUARD2(gCINTMutex);
+
     // CINT still has trouble with std:: sometimes ... 
     if (strncmp(scope_name, "std::", 5) == 0)
         scope_name = &scope_name[5];
 }
 
 cppyy_type_t cppyy_get_template(const char* template_name) {
+    R__LOCKGUARD2(gCINTMutex);
+
     ClassRefIndices_t::iterator icr = g_classref_indices.find(template_name);
     if (icr != g_classref_indices.end())
         return (cppyy_type_t)icr->second;
 }
 
 cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(klass);
     TClass* clActual = cr->GetActualClass( (void*)obj );
     if (clActual && clActual != cr.GetClass()) {
 
 /* memory management ------------------------------------------------------ */
 cppyy_object_t cppyy_allocate(cppyy_type_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     return (cppyy_object_t)malloc(cr->Size());
 }
 }
 
 void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     cr->Destructor((void*)self, true);
 }
 static inline G__value cppyy_call_T(cppyy_method_t method,
         cppyy_object_t self, int nargs, void* args) {
 
+    R__LOCKGUARD2(gCINTMutex);
+
     G__param* libp = (G__param*)((char*)args - offsetof(G__param, para));
     assert(libp->paran == nargs);
     fixup_args(libp);
     G__settemplevel(1);
 
     long index = (long)&method;
-    G__CurrentCall(G__SETMEMFUNCENV, 0, &index);
 
     // TODO: access to store_struct_offset won't work on Windows
     long store_struct_offset = G__store_struct_offset;
     if (G__get_return(0) > G__RETURN_NORMAL)
         G__security_recover(0);    // 0 ensures silence
 
-    G__CurrentCall(G__NOP, 0, 0);
     G__settemplevel(-1);
     G__UnlockCriticalSection();
 
 }
 
 char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    R__LOCKGUARD2(gCINTMutex);
     G__value result = cppyy_call_T(method, self, nargs, args);
     G__pop_tempobject_nodel();
     if (result.ref && *(long*)result.ref) {
 }
 
 cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t handle, int nargs, void* args) {
+    R__LOCKGUARD2(gCINTMutex);
     cppyy_object_t self = (cppyy_object_t)NULL;
     if ((InterpretedFuncs_t::size_type)method >= g_interpreted.size()) {
         G__setgvp((long)G__PVOID);
 
 cppyy_object_t cppyy_call_o(cppyy_type_t method, cppyy_object_t self, int nargs, void* args,
                   cppyy_type_t /*result_type*/ ) {
+    R__LOCKGUARD2(gCINTMutex);
     G__value result = cppyy_call_T(method, self, nargs, args);
     G__pop_tempobject_nodel();
-    return G__int(result);
+    return (cppyy_object_t)G__int(result);
 }
 
 cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /*handle*/, cppyy_index_t /*idx*/) {
 
 /* scope reflection information ------------------------------------------- */
 int cppyy_is_namespace(cppyy_scope_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cr->GetClassInfo())
         return cr->Property() & G__BIT_ISNAMESPACE;
-    if (strcmp(cr.GetClassName(), "") == 0)
+    if (handle == (cppyy_scope_t)GLOBAL_HANDLE)
         return true;
     return false;
 }
 
 int cppyy_is_enum(const char* type_name) {
+    R__LOCKGUARD2(gCINTMutex);
     G__TypeInfo ti(type_name);
     return (ti.Property() & G__BIT_ISENUM);
 }
 
 /* type/class reflection information -------------------------------------- */
 char* cppyy_final_name(cppyy_type_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cr->GetClassInfo()) {
         std::string true_name = G__TypeInfo(cr->GetName()).TrueName();
 }
 
 char* cppyy_scoped_final_name(cppyy_type_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cr->GetClassInfo()) {
         std::string true_name = G__TypeInfo(cr->GetName()).TrueName();
 }
 
 int cppyy_num_bases(cppyy_type_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cr->GetListOfBases() != 0)
         return cr->GetListOfBases()->GetSize();
 }
 
 char* cppyy_base_name(cppyy_type_t handle, int base_index) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     TBaseClass* b = (TBaseClass*)cr->GetListOfBases()->At(base_index);
     return type_cppstring_to_cstring(b->GetName());
 }
 
 int cppyy_is_subtype(cppyy_type_t derived_handle, cppyy_type_t base_handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& derived_type = type_from_handle(derived_handle);
     TClassRef& base_type = type_from_handle(base_handle);
     return derived_type->GetBaseClass(base_type) != 0;
 
 size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle,
                        cppyy_object_t address, int /* direction */) {
+    R__LOCKGUARD2(gCINTMutex);
+
     // WARNING: CINT can not handle actual dynamic casts!
     TClassRef& derived_type = type_from_handle(derived_handle);
     TClassRef& base_type = type_from_handle(base_handle);
 
 /* method/function reflection information --------------------------------- */
 int cppyy_num_methods(cppyy_scope_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cr->GetListOfMethods())
         return cr->GetListOfMethods()->GetSize();
-    else if (strcmp(cr.GetClassName(), "") == 0) {
+    else if (handle == (cppyy_scope_t)GLOBAL_HANDLE) {
         if (g_globalfuncs.empty()) {
             TCollection* funcs = gROOT->GetListOfGlobalFunctions(kTRUE);
 	    g_globalfuncs.reserve(funcs->GetSize());
 }
 
 cppyy_index_t cppyy_method_index_at(cppyy_scope_t handle, int imeth) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass())
         return (cppyy_index_t)imeth;
+    assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
     return (cppyy_index_t)&g_globalfuncs[imeth];
 }
 
 cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t handle, const char* name) {
+    R__LOCKGUARD2(gCINTMutex);
+
     std::vector<cppyy_index_t> result;
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
             }
             ++imeth;
         }
-    }
-
-    if (result.empty()) {
+    } else if (handle == (cppyy_scope_t)GLOBAL_HANDLE) {
         TCollection* funcs = gROOT->GetListOfGlobalFunctions(kTRUE);
         TFunction* func = 0;
         TIter ifunc(funcs);
         while ((func = (TFunction*)ifunc.Next())) {
-            if (strcmp(func->GetName(), name) == 0) {
+            if (strcmp(name, func->GetName()) == 0) {
                 g_globalfuncs.push_back(*func);
                 result.push_back((cppyy_index_t)func); 
             }
     if (result.empty())
         return (cppyy_index_t*)0;
 
-    cppyy_index_t* llresult = (cppyy_index_t*)malloc(sizeof(cppyy_index_t)*result.size()+1);
+    cppyy_index_t* llresult = (cppyy_index_t*)malloc(sizeof(cppyy_index_t)*(result.size()+1));
     for (int i = 0; i < (int)result.size(); ++i) llresult[i] = result[i];
     llresult[result.size()] = -1;
     return llresult;
 
 
 char* cppyy_method_name(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TFunction* f = type_get_method(handle, idx);
     std::string name = f->GetName();
     TClassRef& cr = type_from_handle(handle);
 }
 
 char* cppyy_method_result_type(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cppyy_is_constructor(handle, idx))
         return cppstring_to_cstring("constructor");
 }
 
 int cppyy_method_num_args(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TFunction* f = type_get_method(handle, idx);
     return f->GetNargs();
 }
 
 int cppyy_method_req_args(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TFunction* f = type_get_method(handle, idx);
     return f->GetNargs() - f->GetNargsOpt();
 }
 
 char* cppyy_method_arg_type(cppyy_scope_t handle, cppyy_index_t idx, int arg_index) {
+    R__LOCKGUARD2(gCINTMutex);
     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_signature(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     TFunction* f = type_get_method(handle, idx);
     std::ostringstream sig;
 
 
 int cppyy_method_is_template(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     TFunction* f = type_get_method(handle, idx);
     std::string name = f->GetName();
 
 char* cppyy_method_template_arg_name(
         cppyy_scope_t handle, cppyy_index_t idx, cppyy_index_t /*iarg*/) {
+    R__LOCKGUARD2(gCINTMutex);
 // TODO: return only the name for the requested arg
     TClassRef& cr = type_from_handle(handle);
     TFunction* f = type_get_method(handle, idx);
 
 
 cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
+
     TClassRef& cr = type_from_handle(handle);
     TFunction* f = type_get_method(handle, idx);
     if (cr && cr.GetClass() && !cr->IsLoaded()) {
 }
 
 cppyy_index_t cppyy_get_global_operator(cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op) {
+    R__LOCKGUARD2(gCINTMutex);
+
     TClassRef& lccr = type_from_handle(lc);
     TClassRef& rccr = type_from_handle(rc);
 
-    if (!lccr.GetClass() || !rccr.GetClass() || scope != GLOBAL_HANDLE)
+    if (!lccr.GetClass() || !rccr.GetClass() || scope != (cppyy_scope_t)GLOBAL_HANDLE)
         return (cppyy_index_t)-1;  // (void*)-1 is in kernel space, so invalid as a method handle
 
     std::string lcname = lccr->GetName();
 
 /* method properties -----------------------------------------------------  */
 int cppyy_is_constructor(cppyy_type_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     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, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     TMethod* m = (TMethod*)cr->GetListOfMethods()->At(idx);
     return m->Property() & G__BIT_ISSTATIC;
 
 /* data member reflection information ------------------------------------- */
 int cppyy_num_datamembers(cppyy_scope_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
+
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cr->GetListOfDataMembers())
         return cr->GetListOfDataMembers()->GetSize();
-    else if (strcmp(cr.GetClassName(), "") == 0) {
+    else if (handle == (cppyy_scope_t)GLOBAL_HANDLE) {
         TCollection* vars = gROOT->GetListOfGlobals(kTRUE);
        	if (g_globalvars.size() != (GlobalVars_t::size_type)vars->GetSize()) {
             g_globalvars.clear();
 }
 
 char* cppyy_datamember_name(cppyy_scope_t handle, int datamember_index) {
+    R__LOCKGUARD2(gCINTMutex);
+
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
         return cppstring_to_cstring(m->GetName());
     }
+    assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
     TGlobal& gbl = g_globalvars[datamember_index];
     return cppstring_to_cstring(gbl.GetName());
 }
 
 char* cppyy_datamember_type(cppyy_scope_t handle, int datamember_index) {
+    R__LOCKGUARD2(gCINTMutex);
+
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass())  {
         TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
         }
         return cppstring_to_cstring(fullType);
     }
+    assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
     TGlobal& gbl = g_globalvars[datamember_index];
     return cppstring_to_cstring(gbl.GetFullTypeName());
 }
 
 size_t cppyy_datamember_offset(cppyy_scope_t handle, int datamember_index) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
         return (size_t)m->GetOffsetCint();
     }
+    assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
     TGlobal& gbl = g_globalvars[datamember_index];
     return (size_t)gbl.GetAddress();
 }
 
 int cppyy_datamember_index(cppyy_scope_t handle, const char* name) {
+    R__LOCKGUARD2(gCINTMutex);
+
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         // called from updates; add a hard reset as the code itself caches in
             }
             ++idm;
         }
+    } else if (handle == (cppyy_type_t)GLOBAL_HANDLE) {
+        TGlobal* gbl = (TGlobal*)gROOT->GetListOfGlobals(kTRUE)->FindObject(name);
+        if (!gbl)
+            return -1;
+        int idx = g_globalvars.size();
+        g_globalvars.push_back(*gbl);
+        return idx;
     }
-    TGlobal* gbl = (TGlobal*)gROOT->GetListOfGlobals(kTRUE)->FindObject(name);
-    if (!gbl)
-        return -1;
-    int idx = g_globalvars.size();
-    g_globalvars.push_back(*gbl);
-    return idx;
+    return -1;
 }
 
 
 /* data member properties ------------------------------------------------  */
 int cppyy_is_publicdata(cppyy_scope_t handle, int datamember_index) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
         return m->Property() & G__BIT_ISPUBLIC;
     }
+    assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
     return 1;  // global data is always public
 }
 
 int cppyy_is_staticdata(cppyy_scope_t handle, int datamember_index) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
         return m->Property() & G__BIT_ISSTATIC;
     }
+    assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
     return 1;  // global data is always static
 }
 
     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_load_dictionary(const char* lib_name) {
+    R__LOCKGUARD2(gCINTMutex);
     if (0 <= gSystem->Load(lib_name))
         return (void*)1;
     return (void*)0;
 
 
 /* pythonization helpers -------------------------------------------------- */
+typedef double (*tfn_callback)(double*, double*);
+
+cppyy_object_t cppyy_create_tf1(const char* funcname, unsigned long address,
+        double xmin, double xmax, int npar) {
+    return (cppyy_object_t)new TF1(funcname, (tfn_callback)address, xmin, xmax, npar);
+}
+
 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
 long long cppyy_ttree_GetEntry(void* vtree, long long entry) {
     return (long long)((TTree*)vtree)->GetEntry((Long64_t)entry);
 }
+
+cppyy_object_t cppyy_charp2TString(const char* str) {
+    return (cppyy_object_t)new TString(str);
+}
+
+cppyy_object_t cppyy_TString2TString(cppyy_object_t ptr) {
+    return (cppyy_object_t)new TString(*(TString*)ptr);
+}

pypy/module/cppyy/src/clingcwrapper.cxx

+#include "cppyy.h"
+#include "clingcwrapper.h"
+
+/*************************************************************************
+ * Copyright (C) 1995-2014, the ROOT team.                               *
+ * LICENSE: LGPLv2.1; see http://root.cern.ch/drupal/content/license     *
+ * CONTRIBUTORS: see http://root.cern.ch/drupal/content/contributors     *
+ *************************************************************************/
+
+#include <stdint.h>
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/PrettyPrinter.h"