Author: Matti Picus <matti.pi...@gmail.com>
Branch: unicode-utf8-py3
Changeset: r94791:ab11d063dfa4
Date: 2018-06-30 19:47 -0700
http://bitbucket.org/pypy/pypy/changeset/ab11d063dfa4/

Log:    merge py3.5 into branch

diff too long, truncating to 2000 out of 5287 lines

diff --git a/pypy/doc/sandbox.rst b/pypy/doc/sandbox.rst
--- a/pypy/doc/sandbox.rst
+++ b/pypy/doc/sandbox.rst
@@ -3,6 +3,11 @@
 PyPy's sandboxing features
 ==========================
 
+.. warning:: This is not actively maintained. You will likely have to fix
+   some issues yourself, or otherwise play around on your own. We provide
+   this documentation for historical reasions, it will not translate or
+   run on the latest PyPy code base.
+
 Introduction
 ------------
 
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
@@ -7,9 +7,9 @@
 
 .. branch: cppyy-packaging
 
-Upgrade to backend 0.6.0, support exception handling from wrapped functions,
-update enum handling, const correctness for data members and associated tests,
-support anonymous enums, support for function pointer arguments
+Upgrade to backend 1.1.0, improved handling of templated methods and
+functions (in particular automatic deduction of types), improved pythonization
+interface, and a range of compatibility fixes for Python3
 
 .. branch: socket_default_timeout_blockingness
 
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -270,7 +270,7 @@
         if self.frame is None:
             return     # nothing to do in this case
         space = self.space
-        operr = get_generator_exit(space)
+        operr = None
         # note: w_yielded_from is always None if 'self.running'
         w_yf = self.w_yielded_from
         if w_yf is not None:
@@ -278,6 +278,8 @@
                 self._gen_close_iter(space)
             except OperationError as e:
                 operr = e
+        if operr is None:
+            operr = OperationError(space.w_GeneratorExit, space.w_None)
         try:
             self.send_error(operr)
         except OperationError as e:
@@ -451,11 +453,6 @@
                          space.call_function(space.w_StopIteration, w_value))
 
 
-@specialize.memo()
-def get_generator_exit(space):
-    return OperationError(space.w_GeneratorExit,
-                          space.call_function(space.w_GeneratorExit))
-
 def gen_close_iter(space, w_yf):
     # This helper function is used by close() and throw() to
     # close a subiterator being delegated to by yield-from.
diff --git a/pypy/interpreter/pyparser/automata.py 
b/pypy/interpreter/pyparser/automata.py
--- a/pypy/interpreter/pyparser/automata.py
+++ b/pypy/interpreter/pyparser/automata.py
@@ -23,6 +23,10 @@
 
 ERROR_STATE = chr(255)
 
+# NB: all non-ascii bytes (>= 128) will be turned into 128
+NON_ASCII = chr(128)
+
+
 class DFA:
     # ____________________________________________________________
     def __init__(self, states, accepts, start = 0):
@@ -36,7 +40,10 @@
             for key in state:
                 if key == DEFAULT:
                     continue
-                maximum = max(ord(key), maximum)
+                ordkey = ord(key)
+                if ordkey > 128:
+                    raise ValueError("DFA does not support matching of 
specific non-ASCII character %r. Use NON_ASCII instead" % key)
+                maximum = max(ordkey, maximum)
         self.max_char = maximum + 1
 
         defaults = []
@@ -73,7 +80,7 @@
         for i in range(pos, len(inVec)):
             item = inVec[i]
             if ord(item) > 0x80:
-                item = "\x80"  # NON_ASCII
+                item = NON_ASCII
             accept = self.accepts[crntState]
             crntState = self._next_state(item, crntState)
             if crntState != ERROR_STATE:
@@ -105,6 +112,8 @@
         i = pos
         for i in range(pos, len(inVec)):
             item = inVec[i]
+            if ord(item) > 0x80:
+                item = NON_ASCII
             accept = self.accepts[crntState]
             if accept:
                 return i
diff --git a/pypy/interpreter/pyparser/test/test_automata.py 
b/pypy/interpreter/pyparser/test/test_automata.py
--- a/pypy/interpreter/pyparser/test/test_automata.py
+++ b/pypy/interpreter/pyparser/test/test_automata.py
@@ -1,4 +1,7 @@
-from pypy.interpreter.pyparser.automata import DFA, NonGreedyDFA, DEFAULT
+# coding: utf-8
+import pytest
+
+from pypy.interpreter.pyparser.automata import DFA, NonGreedyDFA, DEFAULT, 
NON_ASCII
 
 def test_states():
     d = DFA([{"\x00": 1}, {"\x01": 0}], [False, True])
@@ -27,3 +30,18 @@
     d = NonGreedyDFA([{"a": 1}, {DEFAULT: 0}], [False, True])
     assert d.recognize("a,a?ab") == 1
     assert d.recognize("c") == -1
+
+def test_nonascii():
+    d = DFA([{"a": 1}, {NON_ASCII: 1}], [False, True])
+    input = u"a&#252;&#252;&#252;&#252;".encode("utf-8")
+    assert d.recognize(input) == len(input)
+    assert d.recognize("c") == -1
+    assert d.recognize("&#252;") == -1
+
+    d = NonGreedyDFA([{NON_ASCII: 0, "b": 1}, {"b": 0}], [False, True])
+    input = u"&#252;&#252;bbbb".encode("utf-8")
+    assert d.recognize(input) == len(u"&#252;&#252;b".encode("utf-8"))
+    assert d.recognize("c") == -1
+
+    pytest.raises(ValueError, DFA, [{"\x81": 2}], [True])
+
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
@@ -170,6 +170,7 @@
         h = get_h()
         raises(ValueError, "f.__code__ = h.__code__")
 
+    @pytest.mark.skipif("config.option.runappdirect")
     def test_write_code_builtin_forbidden(self):
         def f(*args):
             return 42
@@ -339,7 +340,6 @@
         assert meth() == obj
 
     def test_none_get_interaction(self):
-        skip("XXX issue #2083")
         assert type(None).__repr__(None) == 'None'
 
     def test_none_get_interaction_2(self):
@@ -544,7 +544,9 @@
             pass
         r = repr(ClsB().f)
         assert "ClsA.f of <" in r
-        assert "ClsB object at " in r
+        assert repr(type(ClsA.f)) == "<class 'function'>"
+        assert repr(type(ClsA().f)) == "<class 'method'>"
+
 
     def test_method_call(self):
         class C(object):
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,7 @@
 from pypy.interpreter.mixedmodule import MixedModule
 
 class Module(MixedModule):
-    "This module brigdes the cppyy frontend with its backend, through PyPy.\n\
+    "This module bridges the cppyy frontend with its backend, through PyPy.\n\
     See http://cppyy.readthedocs.io/en/latest for full details."
 
     interpleveldefs = {
@@ -14,17 +14,19 @@
         '_set_function_generator': 'interp_cppyy.set_function_generator',
         '_register_class'        : 'interp_cppyy.register_class',
         '_get_nullptr'           : 'interp_cppyy.get_nullptr',
-        'CPPInstanceBase'        : 'interp_cppyy.W_CPPInstance',
+        'CPPInstance'            : 'interp_cppyy.W_CPPInstance',
         'addressof'              : 'interp_cppyy.addressof',
         '_bind_object'           : 'interp_cppyy._bind_object',
         'bind_object'            : 'interp_cppyy.bind_object',
         'move'                   : 'interp_cppyy.move',
+        '_pin_type'              : 'interp_cppyy._pin_type',
     }
 
     appleveldefs = {
         '_post_import_startup'   : 'pythonify._post_import_startup',
+        'Template'               : 'pythonify.CPPTemplate',
         'add_pythonization'      : 'pythonify.add_pythonization',
-        'Template'               : 'pythonify.CPPTemplate',
+        'remove_pythonization'   : 'pythonify.remove_pythonization',
     }
 
     def __init__(self, space, *args):
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
@@ -11,6 +11,3 @@
     assert lltype.typeOf(ptr) == C_OBJECT
     address = rffi.cast(rffi.CCHARP, ptr)
     return rffi.cast(C_OBJECT, lltype.direct_ptradd(address, offset))
-
-def exchange_address(ptr, cif_descr, index):
-    return rffi.ptradd(ptr, cif_descr.exchange_args[index])
diff --git a/pypy/module/_cppyy/capi/loadable_capi.py 
b/pypy/module/_cppyy/capi/loadable_capi.py
--- a/pypy/module/_cppyy/capi/loadable_capi.py
+++ b/pypy/module/_cppyy/capi/loadable_capi.py
@@ -69,7 +69,8 @@
         space = self.space
         cif_descr = self.cif_descr
         size = cif_descr.exchange_size
-        raw_string = rffi.cast(rffi.CCHARP, 0)    # only ever have one in the 
CAPI
+        raw_string1 = rffi.cast(rffi.CCHARP, 0)
+        raw_string2 = rffi.cast(rffi.CCHARP, 0)   # have max two in any CAPI
         buffer = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
         try:
             for i in range(len(args)):
@@ -88,14 +89,18 @@
                     assert obj._voidp != rffi.cast(rffi.VOIDP, 0)
                     data = rffi.cast(rffi.VOIDPP, data)
                     data[0] = obj._voidp
-                else:    # only other use is sring
+                else:    # only other use is string
                     assert obj.tc == 's'
                     n = len(obj._string)
-                    assert raw_string == rffi.cast(rffi.CCHARP, 0)
-                    # XXX could use rffi.get_nonmovingbuffer_final_null()
-                    raw_string = rffi.str2charp(obj._string)
                     data = rffi.cast(rffi.CCHARPP, data)
-                    data[0] = raw_string
+                    if raw_string1 == rffi.cast(rffi.CCHARP, 0):
+                        # XXX could use rffi.get_nonmovingbuffer_final_null()
+                        raw_string1 = rffi.str2charp(obj._string)
+                        data[0] = raw_string1
+                    else:
+                        assert raw_string2 == rffi.cast(rffi.CCHARP, 0)
+                        raw_string2 = rffi.str2charp(obj._string)
+                        data[0] = raw_string2
 
             jit_libffi.jit_ffi_call(cif_descr,
                                     rffi.cast(rffi.VOIDP, funcaddr),
@@ -106,8 +111,10 @@
             # immediate unwrapping, the round-trip is removed
             w_res = self.ctitem.copy_and_convert_to_object(resultdata)
         finally:
-            if raw_string != rffi.cast(rffi.CCHARP, 0):
-                rffi.free_charp(raw_string)
+            if raw_string1 != rffi.cast(rffi.CCHARP, 0):
+                rffi.free_charp(raw_string1)
+            if raw_string2 != rffi.cast(rffi.CCHARP, 0):
+                rffi.free_charp(raw_string2)
             lltype.free(buffer, flavor='raw')
         return w_res
 
@@ -183,8 +190,7 @@
             'constructor'  : ([c_method, c_object, c_int, c_voidp],   
c_object),
             'call_o'       : ([c_method, c_object, c_int, c_voidp, c_type],    
 c_object),
 
-            'function_address_from_index'  : ([c_scope, c_index],     
c_voidp), # TODO: verify
-            'function_address_from_method' : ([c_method],             
c_voidp), # id.
+            'function_address' : ([c_method],                         
c_voidp), # TODO: verify
 
             # handling of function argument buffer
             'allocate_function_args'   : ([c_int],                    c_voidp),
@@ -207,6 +213,8 @@
             'num_bases'                : ([c_type],                   c_int),
             'base_name'                : ([c_type, c_int],            
c_ccharp),
             'is_subtype'               : ([c_type, c_type],           c_int),
+            'smartptr_info'            : ([c_ccharp, c_voidp, c_voidp],        
 c_int),
+            'add_smartptr_type'        : ([c_ccharp],                 c_void),
 
             'base_offset'              : ([c_type, c_type, c_object, c_int],   
 c_ptrdiff_t),
 
@@ -214,30 +222,31 @@
             'num_methods'              : ([c_scope],                  c_int),
             'method_indices_from_name' : ([c_scope, c_ccharp],        
c_index_array),
 
-            'method_name'              : ([c_scope, c_index],         
c_ccharp),
-            'method_mangled_name'      : ([c_scope, c_index],         
c_ccharp),
-            'method_result_type'       : ([c_scope, c_index],         
c_ccharp),
-            'method_num_args'          : ([c_scope, c_index],         c_int),
-            'method_req_args'          : ([c_scope, c_index],         c_int),
-            'method_arg_type'          : ([c_scope, c_index, c_int],  
c_ccharp),
-            'method_arg_default'       : ([c_scope, c_index, c_int],  
c_ccharp),
-            'method_signature'         : ([c_scope, c_index, c_int],  
c_ccharp),
-            'method_prototype'         : ([c_scope, c_index, c_int],  
c_ccharp),
+            'get_method'               : ([c_scope, c_index],         
c_method),
+
+            'method_name'              : ([c_method],                 
c_ccharp),
+            'method_full_name'         : ([c_method],                 
c_ccharp),
+            'method_mangled_name'      : ([c_method],                 
c_ccharp),
+            'method_result_type'       : ([c_method],                 
c_ccharp),
+            'method_num_args'          : ([c_method],                 c_int),
+            'method_req_args'          : ([c_method],                 c_int),
+            'method_arg_type'          : ([c_method, c_int],          
c_ccharp),
+            'method_arg_default'       : ([c_method, c_int],          
c_ccharp),
+            'method_signature'         : ([c_method, c_int],          
c_ccharp),
+            'method_prototype'         : ([c_scope, c_method, c_int], 
c_ccharp),
             'is_const_method'          : ([c_method],                 c_int),
 
             'exists_method_template'   : ([c_scope, c_ccharp],        c_int),
             'method_is_template'       : ([c_scope, c_index],         c_int),
-            'method_num_template_args' : ([c_scope, c_index],         c_int),
-            'method_template_arg_name' : ([c_scope, c_index, c_index],         
 c_ccharp),
+            'get_method_template'      : ([c_scope, c_ccharp, c_ccharp],       
 c_method),
 
-            'get_method'               : ([c_scope, c_index],         
c_method),
             'get_global_operator'      : ([c_scope, c_scope, c_scope, 
c_ccharp],   c_index),
 
             # method properties
-            'is_public_method'         : ([c_type, c_index],          c_int),
-            'is_constructor'           : ([c_type, c_index],          c_int),
-            'is_destructor'            : ([c_type, c_index],          c_int),
-            'is_staticmethod'          : ([c_type, c_index],          c_int),
+            'is_public_method'         : ([c_method],                 c_int),
+            'is_constructor'           : ([c_method],                 c_int),
+            'is_destructor'            : ([c_method],                 c_int),
+            'is_staticmethod'          : ([c_method],                 c_int),
 
             # data member reflection information
             'num_datamembers'          : ([c_scope],                  c_int),
@@ -415,13 +424,9 @@
     args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs), 
_ArgH(cppclass.handle)]
     return _cdata_to_cobject(space, call_capi(space, 'call_o', args))
 
-def c_function_address_from_index(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
+def c_function_address(space, cppmethod):
     return rffi.cast(C_FUNC_PTR,
-        _cdata_to_ptr(space, call_capi(space, 'function_address_from_index', 
args)))
-def c_function_address_from_method(space, cppmethod):
-    return rffi.cast(C_FUNC_PTR,
-        _cdata_to_ptr(space, call_capi(space, 'function_address_from_method', 
[_ArgH(cppmethod)])))
+        _cdata_to_ptr(space, call_capi(space, 'function_address', 
[_ArgH(cppmethod)])))
 
 # handling of function argument buffer ---------------------------------------
 def c_allocate_function_args(space, size):
@@ -479,6 +484,21 @@
     if derived == base:
         return bool(1)
     return space.bool_w(call_capi(space, 'is_subtype', [_ArgH(derived.handle), 
_ArgH(base.handle)]))
+def c_smartptr_info(space, name):
+    out_raw   = lltype.malloc(rffi.ULONGP.TO, 1, flavor='raw', zero=True)
+    out_deref = lltype.malloc(rffi.ULONGP.TO, 1, flavor='raw', zero=True)
+    try:
+        args = [_ArgS(name),
+           _ArgP(rffi.cast(rffi.VOIDP, out_raw)), _ArgP(rffi.cast(rffi.VOIDP, 
out_deref))]
+        result = space.bool_w(call_capi(space, 'smartptr_info', args))
+        raw   = rffi.cast(C_TYPE, out_raw[0])
+        deref = rffi.cast(C_METHOD, out_deref[0])
+    finally:
+        lltype.free(out_deref, flavor='raw')
+        lltype.free(out_raw, flavor='raw')
+    return (result, raw, deref)
+def c_add_smartptr_type(space, name):
+    return space.bool_w(call_capi(space, 'add_smartptr_type', [_ArgS(name)]))
 
 def _c_base_offset(space, derived_h, base_h, address, direction):
     args = [_ArgH(derived_h), _ArgH(base_h), _ArgH(address), _ArgL(direction)]
@@ -510,30 +530,36 @@
     c_free(space, rffi.cast(rffi.VOIDP, indices))   # c_free defined below
     return py_indices
 
-def c_method_name(space, cppscope, index):
+def c_get_method(space, cppscope, index):
     args = [_ArgH(cppscope.handle), _ArgL(index)]
-    return charp2str_free(space, call_capi(space, 'method_name', args))
-def c_method_result_type(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
-    return charp2str_free(space, call_capi(space, 'method_result_type', args))
-def c_method_num_args(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
-    return space.int_w(call_capi(space, 'method_num_args', args))
-def c_method_req_args(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
-    return space.int_w(call_capi(space, 'method_req_args', args))
-def c_method_arg_type(space, cppscope, index, arg_index):
-    args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(arg_index)]
+    return rffi.cast(C_METHOD, space.uint_w(call_capi(space, 'get_method', 
args)))
+
+def c_method_name(space, cppmeth):
+    return charp2str_free(space, call_capi(space, 'method_name', 
[_ArgH(cppmeth)]))
+def c_method_full_name(space, cppmeth):
+    return charp2str_free(space, call_capi(space, 'method_full_name', 
[_ArgH(cppmeth)]))
+def c_method_mangled_name(space, cppmeth):
+    return charp2str_free(space, call_capi(space, 'method_mangled_name', 
[_ArgH(cppmeth)]))
+def c_method_result_type(space, cppmeth):
+    return charp2str_free(space, call_capi(space, 'method_result_type', 
[_ArgH(cppmeth)]))
+def c_method_num_args(space, cppmeth):
+    return space.int_w(call_capi(space, 'method_num_args', [_ArgH(cppmeth)]))
+def c_method_req_args(space, cppmeth):
+    return space.int_w(call_capi(space, 'method_req_args', [_ArgH(cppmeth)]))
+def c_method_arg_type(space, cppmeth, arg_index):
+    args = [_ArgH(cppmeth), _ArgL(arg_index)]
     return charp2str_free(space, call_capi(space, 'method_arg_type', args))
-def c_method_arg_default(space, cppscope, index, arg_index):
-    args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(arg_index)]
+def c_method_arg_default(space, cppmeth, arg_index):
+    args = [_ArgH(cppmeth), _ArgL(arg_index)]
     return charp2str_free(space, call_capi(space, 'method_arg_default', args))
-def c_method_signature(space, cppscope, index, show_formalargs=True):
-    args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(show_formalargs)]
+def c_method_signature(space, cppmeth, show_formalargs=True):
+    args = [_ArgH(cppmeth), _ArgL(show_formalargs)]
     return charp2str_free(space, call_capi(space, 'method_signature', args))
-def c_method_prototype(space, cppscope, index, show_formalargs=True):
-    args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(show_formalargs)]
+def c_method_prototype(space, cppscope, cppmeth, show_formalargs=True):
+    args = [_ArgH(cppscope.handle), _ArgH(cppmeth), _ArgL(show_formalargs)]
     return charp2str_free(space, call_capi(space, 'method_prototype', args))
+def c_is_const_method(space, cppmeth):
+    return space.bool_w(call_capi(space, 'is_const_method', [_ArgH(cppmeth)]))
 
 def c_exists_method_template(space, cppscope, name):
     args = [_ArgH(cppscope.handle), _ArgS(name)]
@@ -541,21 +567,10 @@
 def c_method_is_template(space, cppscope, index):
     args = [_ArgH(cppscope.handle), _ArgL(index)]
     return space.bool_w(call_capi(space, 'method_is_template', args))
-def _c_method_num_template_args(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
-    return space.int_w(call_capi(space, 'method_num_template_args', args)) 
-def c_template_args(space, cppscope, index):
-    nargs = _c_method_num_template_args(space, cppscope, index)
-    arg1 = _ArgH(cppscope.handle)
-    arg2 = _ArgL(index)
-    args = [c_resolve_name(space, charp2str_free(space,
-                call_capi(space, 'method_template_arg_name', [arg1, arg2, 
_ArgL(iarg)]))
-            ) for iarg in range(nargs)]
-    return args
 
-def c_get_method(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
-    return rffi.cast(C_METHOD, space.uint_w(call_capi(space, 'get_method', 
args)))
+def c_get_method_template(space, cppscope, name, proto):
+    args = [_ArgH(cppscope.handle), _ArgS(name), _ArgS(proto)]
+    return rffi.cast(C_METHOD, space.uint_w(call_capi(space, 
'get_method_template', args)))
 def c_get_global_operator(space, nss, lc, rc, op):
     if nss is not None:
         args = [_ArgH(nss.handle), _ArgH(lc.handle), _ArgH(rc.handle), 
_ArgS(op)]
@@ -563,18 +578,14 @@
     return rffi.cast(WLAVC_INDEX, -1)
 
 # method properties ----------------------------------------------------------
-def c_is_public_method(space, cppclass, index):
-    args = [_ArgH(cppclass.handle), _ArgL(index)]
-    return space.bool_w(call_capi(space, 'is_public_method', args))
-def c_is_constructor(space, cppclass, index):
-    args = [_ArgH(cppclass.handle), _ArgL(index)]
-    return space.bool_w(call_capi(space, 'is_constructor', args))
-def c_is_destructor(space, cppclass, index):
-    args = [_ArgH(cppclass.handle), _ArgL(index)]
-    return space.bool_w(call_capi(space, 'is_destructor', args))
-def c_is_staticmethod(space, cppclass, index):
-    args = [_ArgH(cppclass.handle), _ArgL(index)]
-    return space.bool_w(call_capi(space, 'is_staticmethod', args))
+def c_is_public_method(space, cppmeth):
+    return space.bool_w(call_capi(space, 'is_public_method', [_ArgH(cppmeth)]))
+def c_is_constructor(space, cppmeth):
+    return space.bool_w(call_capi(space, 'is_constructor', [_ArgH(cppmeth)]))
+def c_is_destructor(space, cppmeth):
+    return space.bool_w(call_capi(space, 'is_destructor', [_ArgH(cppmeth)]))
+def c_is_staticmethod(space, cppmeth):
+    return space.bool_w(call_capi(space, 'is_staticmethod', [_ArgH(cppmeth)]))
 
 # data member reflection information -----------------------------------------
 def c_num_datamembers(space, cppscope):
@@ -676,7 +687,7 @@
     space.setattr(w_pycppclass, space.newtext(m1),
                   space.getattr(w_pycppclass, space.newtext(m2)))
 
-def pythonize(space, name, w_pycppclass):
+def pythonize(space, w_pycppclass, name):
     if name == "string":
         space.setattr(w_pycppclass, space.newtext("c_str"), 
_pythonizations["stdstring_c_str"])
         _method_alias(space, w_pycppclass, "_cppyy_as_builtin", "c_str")
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
@@ -7,7 +7,7 @@
 from rpython.rlib import rfloat, rawrefcount
 
 from pypy.module._rawffi.interp_rawffi import letter2tp
-from pypy.module._rawffi.array import W_Array, W_ArrayInstance
+from pypy.module._rawffi.array import W_ArrayInstance
 
 from pypy.module._cppyy import helper, capi, ffitypes
 
@@ -68,6 +68,8 @@
         pass
     # array type
     try:
+        if hasattr(space, "fake"):
+            raise NotImplementedError
         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)))
@@ -130,20 +132,6 @@
         pass
 
 
-class ArrayCache(object):
-    def __init__(self, space):
-        self.space = space
-    def __getattr__(self, name):
-        if name.startswith('array_'):
-            typecode = name[len('array_'):]
-            arr = self.space.interp_w(W_Array, letter2tp(self.space, typecode))
-            setattr(self, name, arr)
-            return arr
-        raise AttributeError(name)
-
-    def _freeze_(self):
-        return True
-
 class ArrayTypeConverterMixin(object):
     _mixin_ = True
     _immutable_fields_ = ['size']
@@ -162,9 +150,7 @@
         # read access, so no copy needed
         address_value = self._get_raw_address(space, w_obj, offset)
         address = rffi.cast(rffi.ULONG, address_value)
-        cache = space.fromcache(ArrayCache)
-        arr = getattr(cache, 'array_' + self.typecode)
-        return arr.fromaddress(space, address, self.size)
+        return W_ArrayInstance(space, letter2tp(space, self.typecode), 
self.size, address)
 
     def to_memory(self, space, w_obj, w_value, offset):
         # copy the full array (uses byte copy for now)
@@ -205,17 +191,15 @@
         # read access, so no copy needed
         address_value = self._get_raw_address(space, w_obj, offset)
         address = rffi.cast(rffi.ULONGP, address_value)
-        cache = space.fromcache(ArrayCache)
-        arr = getattr(cache, 'array_' + self.typecode)
-        return arr.fromaddress(space, address[0], self.size)
+        return W_ArrayInstance(space, letter2tp(space, self.typecode), 
self.size, address[0])
 
     def to_memory(self, space, w_obj, w_value, offset):
         # copy only the pointer value
         rawobject = get_rawobject_nonnull(space, w_obj)
-        byteptr = rffi.cast(rffi.CCHARPP, capi.direct_ptradd(rawobject, 
offset))
+        byteptr = rffi.cast(rffi.VOIDPP, capi.direct_ptradd(rawobject, offset))
         buf = space.getarg_w('s*', w_value)
         try:
-            byteptr[0] = buf.get_raw_address()
+            byteptr[0] = rffi.cast(rffi.VOIDP, buf.get_raw_address())
         except ValueError:
             raise oefmt(space.w_TypeError,
                         "raw buffer interface not supported")
@@ -337,6 +321,10 @@
         address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, 
offset))
         address[0] = self._unwrap_object(space, w_value)
 
+
+class UCharConverter(ffitypes.typeid(rffi.UCHAR), CharConverter):
+    pass
+
 class FloatConverter(ffitypes.typeid(rffi.FLOAT), FloatTypeConverterMixin, 
TypeConverter):
     _immutable_fields_ = ['default']
 
@@ -398,12 +386,12 @@
         arg = space.text_w(w_obj)
         x[0] = rffi.cast(rffi.LONG, rffi.str2charp(arg))
         ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset(space)] = 'o'
+        ba[capi.c_function_arg_typeoffset(space)] = 'p'
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = self._get_raw_address(space, w_obj, offset)
         charpptr = rffi.cast(rffi.CCHARPP, address)
-        return space.newbytes(rffi.charp2str(charpptr[0]))
+        return space.newtext(rffi.charp2str(charpptr[0]))
 
     def free_argument(self, space, arg, call_local):
         lltype.free(rffi.cast(rffi.CCHARPP, arg)[0], flavor='raw')
@@ -420,7 +408,7 @@
         strsize = self.size
         if charpptr[self.size-1] == '\0':
             strsize = self.size-1  # rffi will add \0 back
-        return space.newbytes(rffi.charpsize2str(charpptr, strsize))
+        return space.newtext(rffi.charpsize2str(charpptr, strsize))
 
 
 class VoidPtrConverter(TypeConverter):
@@ -449,12 +437,12 @@
         # 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:
+        ptrval = rffi.cast(rffi.ULONGP, address)[0]
+        if ptrval == rffi.cast(rffi.ULONG, 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)
+        shape = letter2tp(space, 'P')
+        return W_ArrayInstance(space, shape, sys.maxint/shape.size, ptrval)
 
     def to_memory(self, space, w_obj, w_value, offset):
         address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, 
offset))
@@ -504,8 +492,8 @@
     def _unwrap_object(self, space, w_obj):
         from pypy.module._cppyy.interp_cppyy import W_CPPInstance
         if isinstance(w_obj, W_CPPInstance):
-            from pypy.module._cppyy.interp_cppyy import 
INSTANCE_FLAGS_IS_R_VALUE
-            if w_obj.flags & INSTANCE_FLAGS_IS_R_VALUE:
+            from pypy.module._cppyy.interp_cppyy import 
INSTANCE_FLAGS_IS_RVALUE
+            if w_obj.flags & INSTANCE_FLAGS_IS_RVALUE:
                 # reject moves as all are explicit
                 raise ValueError("lvalue expected")
             if capi.c_is_subtype(space, w_obj.clsdecl, self.clsdecl):
@@ -514,7 +502,7 @@
                 obj_address = capi.direct_ptradd(rawobject, offset)
                 return rffi.cast(capi.C_OBJECT, obj_address)
         raise oefmt(space.w_TypeError,
-                    "cannot pass %T as %s", w_obj, self.clsdecl.name)
+                    "cannot pass %T instance as %s", w_obj, self.clsdecl.name)
 
     def cffi_type(self, space):
         state = space.fromcache(ffitypes.State)
@@ -534,11 +522,18 @@
 class InstanceMoveConverter(InstanceRefConverter):
     def _unwrap_object(self, space, w_obj):
         # moving is same as by-ref, but have to check that move is allowed
-        from pypy.module._cppyy.interp_cppyy import W_CPPInstance, 
INSTANCE_FLAGS_IS_R_VALUE
-        if isinstance(w_obj, W_CPPInstance):
-            if w_obj.flags & INSTANCE_FLAGS_IS_R_VALUE:
-                w_obj.flags &= ~INSTANCE_FLAGS_IS_R_VALUE
-                return InstanceRefConverter._unwrap_object(self, space, w_obj)
+        from pypy.module._cppyy.interp_cppyy import W_CPPInstance, 
INSTANCE_FLAGS_IS_RVALUE
+        obj = space.interp_w(W_CPPInstance, w_obj)
+        if obj:
+            if obj.flags & INSTANCE_FLAGS_IS_RVALUE:
+                obj.flags &= ~INSTANCE_FLAGS_IS_RVALUE
+                try:
+                    return InstanceRefConverter._unwrap_object(self, space, 
w_obj)
+                except Exception:
+                    # TODO: if the method fails on some other converter, then 
the next
+                    # overload can not be an rvalue anymore
+                    obj.flags |= INSTANCE_FLAGS_IS_RVALUE
+                    raise
         raise oefmt(space.w_ValueError, "object is not an rvalue")
 
 
@@ -629,8 +624,7 @@
             address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, 
w_obj, offset))
             assign = self.clsdecl.get_overload("__assign__")
             from pypy.module._cppyy import interp_cppyy
-            assign.call(
-                interp_cppyy.wrap_cppinstance(space, address, self.clsdecl, 
do_cast=False), [w_value])
+            assign.call_impl(address, [w_value])
         except Exception:
             InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
 
@@ -639,7 +633,6 @@
 
 class StdStringRefConverter(InstancePtrConverter):
     _immutable_fields_ = ['cppclass', 'typecode']
-
     typecode    = 'V'
 
     def __init__(self, space, extra):
@@ -702,8 +695,7 @@
             m = cppol.functions[i]
             if m.signature(False) == self.signature:
                 x = rffi.cast(rffi.VOIDPP, address)
-                x[0] = rffi.cast(rffi.VOIDP,
-                    capi.c_function_address_from_method(space, m.cppmethod))
+                x[0] = rffi.cast(rffi.VOIDP, capi.c_function_address(space, 
m.cppmethod))
                 address = rffi.cast(capi.C_OBJECT, address)
                 ba = rffi.cast(rffi.CCHARP, address)
                 ba[capi.c_function_arg_typeoffset(space)] = 'p'
@@ -714,6 +706,67 @@
                     "no overload found matching %s", self.signature)
 
 
+class SmartPtrConverter(TypeConverter):
+    _immutable_fields = ['typecode', 'smartdecl', 'rawdecl', 'deref']
+    typecode    = 'V'
+
+    def __init__(self, space, smartdecl, raw, deref):
+        from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl, 
get_pythonized_cppclass
+        self.smartdecl = smartdecl
+        w_raw   = get_pythonized_cppclass(space, raw)
+        self.rawdecl   = space.interp_w(W_CPPClassDecl,
+            space.findattr(w_raw, space.newtext("__cppdecl__")))
+        self.deref     = deref
+
+    def _unwrap_object(self, space, w_obj):
+        from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+        if isinstance(w_obj, W_CPPInstance):
+            # w_obj could carry a 'hidden' smart ptr or be one, cover both 
cases
+            have_match = False
+            if w_obj.smartdecl and capi.c_is_subtype(space, w_obj.smartdecl, 
self.smartdecl):
+                # hidden case, do not derefence when getting obj address
+                have_match = True
+                rawobject = w_obj._rawobject      # TODO: this direct access 
if fugly
+                offset = capi.c_base_offset(space, w_obj.smartdecl, 
self.smartdecl, rawobject, 1)
+            elif capi.c_is_subtype(space, w_obj.clsdecl, self.smartdecl):
+                # exposed smart pointer
+                have_match = True
+                rawobject = w_obj.get_rawobject()
+                offset = capi.c_base_offset(space, w_obj.clsdecl, 
self.smartdecl, rawobject, 1)
+            if have_match:
+                obj_address = capi.direct_ptradd(rawobject, offset)
+                return rffi.cast(capi.C_OBJECT, obj_address)
+
+        raise oefmt(space.w_TypeError,
+                    "cannot pass %T instance as %s", w_obj, self.rawdecl.name)
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
+        address = rffi.cast(capi.C_OBJECT, address)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset(space)] = self.typecode
+
+    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_cppinstance(space, address,
+            self.rawdecl, smartdecl=self.smartdecl, deref=self.deref, 
do_cast=False)
+
+class SmartPtrPtrConverter(SmartPtrConverter):
+    typecode    = 'o'
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        self._is_abstract(space)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        self._is_abstract(space)
+
+
+class SmartPtrRefConverter(SmartPtrPtrConverter):
+    typecode    = 'V'
+
+
 class MacroConverter(TypeConverter):
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         # TODO: get the actual type info from somewhere ...
@@ -729,44 +782,61 @@
     #   1) full, exact match
     #       1a) const-removed match
     #   2) match of decorated, unqualified type
-    #   3) accept ref as pointer (for the stubs, const& can be
-    #       by value, but that does not work for the ffi path)
-    #   4) generalized cases (covers basically all user classes)
-    #   5) void* or void converter (which fails on use)
+    #   3) generalized cases (covers basically all user classes)
+    #       3a) smart pointers
+    #   4) void* or void converter (which fails on use)
 
     name = capi.c_resolve_name(space, _name)
 
-    #   1) full, exact match
+    # full, exact match
     try:
         return _converters[name](space, default)
     except KeyError:
         pass
 
-    #   1a) const-removed match
+    # const-removed match
     try:
         return _converters[helper.remove_const(name)](space, default)
     except KeyError:
         pass
 
-    #   2) match of decorated, unqualified type
+    # match of decorated, unqualified type
     compound = helper.compound(name)
     clean_name = capi.c_resolve_name(space, helper.clean_type(name))
     try:
+        return _converters[clean_name+compound](space, default)
+    except KeyError:
+        pass
+
+    # arrays
+    try:
         # array_index may be negative to indicate no size or no size found
         array_size = helper.array_size(_name)     # uses original arg
+        # TODO: using clean_name here drops const (e.g. const char[] will
+        # never be seen this way)
         return _a_converters[clean_name+compound](space, array_size)
     except KeyError:
         pass
 
-    #   3) TODO: accept ref as pointer
-
-    #   4) generalized cases (covers basically all user classes)
+    # generalized cases (covers basically all user classes)
     from pypy.module._cppyy import interp_cppyy
     scope_decl = interp_cppyy.scope_byname(space, clean_name)
     if scope_decl:
-        # type check for the benefit of the annotator
         from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl
         clsdecl = space.interp_w(W_CPPClassDecl, scope_decl, can_be_None=False)
+
+        # check smart pointer type
+        check_smart = capi.c_smartptr_info(space, clean_name)
+        if check_smart[0]:
+            if compound == '':
+                return SmartPtrConverter(space, clsdecl, check_smart[1], 
check_smart[2])
+            elif compound == '*':
+                return SmartPtrPtrConverter(space, clsdecl, check_smart[1], 
check_smart[2])
+            elif compound == '&':
+                return SmartPtrRefConverter(space, clsdecl, check_smart[1], 
check_smart[2])
+            # fall through: can still return smart pointer in non-smart way
+
+        # type check for the benefit of the annotator
         if compound == "*":
             return InstancePtrConverter(space, clsdecl)
         elif compound == "&":
@@ -786,7 +856,7 @@
         if pos > 0:
             return FunctionPointerConverter(space, name[pos+2:])
 
-    #   5) void* or void converter (which fails on use)
+    # void* or void converter (which fails on use)
     if 0 <= compound.find('*'):
         return VoidPtrConverter(space, default)  # "user knows best"
 
@@ -797,6 +867,7 @@
 
 _converters["bool"]                     = BoolConverter
 _converters["char"]                     = CharConverter
+_converters["unsigned char"]            = UCharConverter
 _converters["float"]                    = FloatConverter
 _converters["const float&"]             = ConstFloatRefConverter
 _converters["double"]                   = DoubleConverter
@@ -886,6 +957,7 @@
     "NOT_RPYTHON"
     array_info = (
         ('b', rffi.sizeof(rffi.UCHAR),      ("bool",)),    # is debatable, but 
works ...
+        ('B', rffi.sizeof(rffi.UCHAR),      ("unsigned char",)),
         ('h', rffi.sizeof(rffi.SHORT),      ("short int", "short")),
         ('H', rffi.sizeof(rffi.USHORT),     ("unsigned short int", "unsigned 
short")),
         ('i', rffi.sizeof(rffi.INT),        ("int",)),
@@ -901,9 +973,11 @@
 
     for tcode, tsize, names in array_info:
         class ArrayConverter(ArrayTypeConverterMixin, TypeConverter):
+            _immutable_fields_ = ['typecode', 'typesize']
             typecode = tcode
             typesize = tsize
         class PtrConverter(PtrTypeConverterMixin, TypeConverter):
+            _immutable_fields_ = ['typecode', 'typesize']
             typecode = tcode
             typesize = tsize
         for name in names:
@@ -912,6 +986,7 @@
 
     # special case, const char* w/ size and w/o '\0'
     _a_converters["const char[]"] = CStringConverterWithSize
+    _a_converters["char[]"]       = _a_converters["const char[]"]     # 
debatable
 
 _build_array_converters()
 
@@ -919,7 +994,6 @@
 def _add_aliased_converters():
     "NOT_RPYTHON"
     aliases = (
-        ("char",                            "unsigned char"), # TODO: check
         ("char",                            "signed char"),   # TODO: check
         ("const char*",                     "char*"),
 
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
@@ -5,7 +5,7 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib import jit_libffi
 
-from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+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
@@ -26,7 +26,7 @@
 
 NULL = lltype.nullptr(jit_libffi.FFI_TYPE_P.TO)
 
-class FunctionExecutor(object):
+class Executor(object):
     def __init__(self, space, extra):
         pass
 
@@ -43,7 +43,7 @@
         raise FastCallNotPossible
 
 
-class PtrTypeExecutor(FunctionExecutor):
+class PtrTypeExecutor(Executor):
     _immutable_fields_ = ['typecode']
     typecode = 'P'
 
@@ -56,14 +56,14 @@
             raise NotImplementedError
         lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
         ptrval = rffi.cast(rffi.ULONG, lresult)
-        arr = space.interp_w(W_Array, unpack_simple_shape(space, 
space.newtext(self.typecode)))
-        if ptrval == 0:
+        if ptrval == rffi.cast(rffi.ULONG, 0):
             from pypy.module._cppyy import interp_cppyy
             return interp_cppyy.get_nullptr(space)
-        return arr.fromaddress(space, ptrval, sys.maxint)
+        shape = letter2tp(space, self.typecode)
+        return W_ArrayInstance(space, shape, sys.maxint/shape.size, ptrval)
 
 
-class VoidExecutor(FunctionExecutor):
+class VoidExecutor(Executor):
     def cffi_type(self, space):
         state = space.fromcache(ffitypes.State)
         return state.c_void
@@ -96,7 +96,7 @@
     _mixin_ = True
 
     def __init__(self, space, extra):
-        FunctionExecutor.__init__(self, space, extra)
+        Executor.__init__(self, space, extra)
         self.do_assign = False
         self.item = rffi.cast(self.c_type, 0)
 
@@ -124,8 +124,7 @@
             rffi.cast(self.c_ptrtype, rffi.cast(rffi.VOIDPP, result)[0]))
 
 
-class CStringExecutor(FunctionExecutor):
-
+class CStringExecutor(Executor):
     def execute(self, space, cppmethod, cppthis, num_args, args):
         lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
         ccpresult = rffi.cast(rffi.CCHARP, lresult)
@@ -139,8 +138,7 @@
         return space.newtext(result)
 
 
-class ConstructorExecutor(FunctionExecutor):
-
+class ConstructorExecutor(Executor):
     def execute(self, space, cppmethod, cpptype, num_args, args):
         from pypy.module._cppyy import interp_cppyy
         newthis = capi.c_constructor(space, cppmethod, cpptype, num_args, args)
@@ -148,80 +146,77 @@
         return space.newlong(rffi.cast(rffi.LONG, newthis))   # really want 
ptrdiff_t here
 
 
-class InstancePtrExecutor(FunctionExecutor):
-    _immutable_fields_ = ['cppclass']
+class InstanceExecutor(Executor):
+    # For return of a C++ instance by pointer: MyClass* func()
+    _immutable_fields_ = ['clsdecl']
 
-    def __init__(self, space, cppclass):
-        FunctionExecutor.__init__(self, space, cppclass)
-        self.cppclass = cppclass
+    def __init__(self, space, clsdecl):
+        Executor.__init__(self, space, clsdecl)
+        self.clsdecl = clsdecl
+
+    def _wrap_result(self, space, obj):
+        from pypy.module._cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppinstance(space,
+            obj, self.clsdecl, do_cast=False, python_owns=True, fresh=True)
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        oresult = capi.c_call_o(space, cppmethod, cppthis, num_args, args, 
self.clsdecl)
+        return self._wrap_result(space, rffi.cast(capi.C_OBJECT, oresult))
+
+
+class InstancePtrExecutor(InstanceExecutor):
+    # For return of a C++ instance by pointer: MyClass* func()
 
     def cffi_type(self, space):
         state = space.fromcache(ffitypes.State)
         return state.c_voidp
 
+    def _wrap_result(self, space, obj):
+        from pypy.module._cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppinstance(space, obj, self.clsdecl)
+
     def execute(self, space, cppmethod, cppthis, num_args, args):
-        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)
-        pyres = interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
-        return pyres
+        lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, rffi.cast(capi.C_OBJECT, lresult))
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
-        result = rffi.ptradd(buffer, cif_descr.exchange_result)
-        from pypy.module._cppyy import interp_cppyy
-        ptr_result = rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, 
result)[0])
-        return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
+        presult = rffi.ptradd(buffer, cif_descr.exchange_result)
+        obj = rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, presult)[0])
+        return self._wrap_result(space, obj)
 
 class InstancePtrPtrExecutor(InstancePtrExecutor):
+    # For return of a C++ instance by ptr-to-ptr or ptr-to-ref: MyClass*& 
func()
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
-        from pypy.module._cppyy import interp_cppyy
-        voidp_result = capi.c_call_r(space, cppmethod, cppthis, num_args, args)
-        ref_address = rffi.cast(rffi.VOIDPP, voidp_result)
-        ptr_result = rffi.cast(capi.C_OBJECT, ref_address[0])
-        return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
+        presult = capi.c_call_r(space, cppmethod, cppthis, num_args, args)
+        ref = rffi.cast(rffi.VOIDPP, presult)
+        return self._wrap_result(space, rffi.cast(capi.C_OBJECT, ref[0]))
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
-class InstanceExecutor(InstancePtrExecutor):
-
-    def execute(self, space, cppmethod, cppthis, num_args, args):
-        from pypy.module._cppyy import interp_cppyy
-        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_cppinstance(space, ptr_result, self.cppclass,
-                                             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
-        raise FastCallNotPossible
-
 
 class StdStringExecutor(InstancePtrExecutor):
-
     def execute(self, space, cppmethod, cppthis, num_args, args):
         cstr, cstr_len = capi.c_call_s(space, cppmethod, cppthis, num_args, 
args)
         pystr = rffi.charpsize2str(cstr, cstr_len)
         capi.c_free(space, rffi.cast(rffi.VOIDP, cstr))
-        return space.newbytes(pystr)
+        return space.newbytes(pystr) 
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
 class StdStringRefExecutor(InstancePtrExecutor):
-
-    def __init__(self, space, cppclass):
+    def __init__(self, space, clsdecl):
         from pypy.module._cppyy import interp_cppyy
-        cppclass = interp_cppyy.scope_byname(space, capi.std_string_name)
-        InstancePtrExecutor.__init__(self, space, cppclass)
+        clsdecl = interp_cppyy.scope_byname(space, capi.std_string_name)
+        InstancePtrExecutor.__init__(self, space, clsdecl)
 
 
 class PyObjectExecutor(PtrTypeExecutor):
-
     def wrap_result(self, space, lresult):
         space.getbuiltinmodule("cpyext")
         from pypy.module.cpyext.pyobject import PyObject, from_ref, make_ref, 
decref
@@ -245,6 +240,41 @@
         return self.wrap_result(space, rffi.cast(rffi.LONGP, result)[0])
 
 
+class SmartPointerExecutor(InstanceExecutor):
+    _immutable_fields_ = ['smartdecl', 'deref']
+
+    def __init__(self, space, smartdecl, raw, deref):
+        from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl, 
get_pythonized_cppclass
+        w_raw   = get_pythonized_cppclass(space, raw)
+        rawdecl = space.interp_w(W_CPPClassDecl, space.findattr(w_raw, 
space.newtext("__cppdecl__")))
+        InstanceExecutor.__init__(self, space, rawdecl)
+        self.smartdecl = smartdecl
+        self.deref     = deref
+
+    def _wrap_result(self, space, obj):
+        from pypy.module._cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppinstance(space, obj, self.clsdecl,
+            self.smartdecl, self.deref, do_cast=False, python_owns=True, 
fresh=True)
+
+class SmartPointerPtrExecutor(InstancePtrExecutor):
+    _immutable_fields_ = ['smartdecl', 'deref']
+
+    def __init__(self, space, smartdecl, raw, deref):
+        # TODO: share this with SmartPointerExecutor through in mixin
+        from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl, 
get_pythonized_cppclass
+        w_raw   = get_pythonized_cppclass(space, raw)
+        rawdecl = space.interp_w(W_CPPClassDecl, space.findattr(w_raw, 
space.newtext("__cppdecl__")))
+        InstancePtrExecutor.__init__(self, space, rawdecl)
+        self.smartdecl = smartdecl
+        self.deref     = deref
+
+    def _wrap_result(self, space, obj):
+        from pypy.module._cppyy import interp_cppyy
+        # TODO: this is a pointer to a smart pointer, take ownership on the 
smart one?
+        return interp_cppyy.wrap_cppinstance(space, obj, self.clsdecl,
+            self.smartdecl, self.deref, do_cast=False)
+
+
 _executors = {}
 def get_executor(space, name):
     # Matching of 'name' to an executor factory goes through up to four levels:
@@ -257,7 +287,7 @@
 
     name = capi.c_resolve_name(space, name)
 
-    #   1) full, qualified match
+    # full, qualified match
     try:
         return _executors[name](space, None)
     except KeyError:
@@ -266,13 +296,13 @@
     compound = helper.compound(name)
     clean_name = capi.c_resolve_name(space, helper.clean_type(name))
 
-    #   1a) clean lookup
+    # clean lookup
     try:
         return _executors[clean_name+compound](space, None)
     except KeyError:
         pass
 
-    #   2) drop '&': by-ref is pretty much the same as by-value, python-wise
+    # drop '&': by-ref is pretty much the same as by-value, python-wise
     if compound and compound[len(compound)-1] == '&':
         # TODO: this does not actually work with Reflex (?)
         try:
@@ -280,19 +310,29 @@
         except KeyError:
             pass
 
-    #   3) types/classes, either by ref/ptr or by value
+    # types/classes, either by ref/ptr or by value
     from pypy.module._cppyy import interp_cppyy
     cppclass = interp_cppyy.scope_byname(space, clean_name)
     if cppclass:
         # type check for the benefit of the annotator
         from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl
-        cppclass = space.interp_w(W_CPPClassDecl, cppclass, can_be_None=False)
+        clsdecl = space.interp_w(W_CPPClassDecl, cppclass, can_be_None=False)
+
+        # check smart pointer type
+        check_smart = capi.c_smartptr_info(space, clean_name)
+        if check_smart[0]:
+            if compound == '':
+                return SmartPointerExecutor(space, clsdecl, check_smart[1], 
check_smart[2])
+            elif compound == '*' or compound == '&':
+                return SmartPointerPtrExecutor(space, clsdecl, check_smart[1], 
check_smart[2])
+            # fall through: can still return smart pointer in non-smart way
+
         if compound == '':
-            return InstanceExecutor(space, cppclass)
+            return InstanceExecutor(space, clsdecl)
         elif compound == '*' or compound == '&':
-            return InstancePtrExecutor(space, cppclass)
+            return InstancePtrExecutor(space, clsdecl)
         elif compound == '**' or compound == '*&':
-            return InstancePtrPtrExecutor(space, cppclass)
+            return InstancePtrPtrExecutor(space, clsdecl)
     elif "(anonymous)" in name:
         # special case: enum w/o a type name
         return _executors["internal_enum_type_t"](space, None)
@@ -302,7 +342,7 @@
         return _executors['void*'](space, None)  # allow at least passing of 
the pointer
 
     # currently used until proper lazy instantiation available in interp_cppyy
-    return FunctionExecutor(space, None)
+    return Executor(space, None)
  
 
 _executors["void"]                = VoidExecutor
@@ -338,10 +378,10 @@
     )
 
     for c_type, stub, names in type_info:
-        class BasicExecutor(ffitypes.typeid(c_type), NumericExecutorMixin, 
FunctionExecutor):
+        class BasicExecutor(ffitypes.typeid(c_type), NumericExecutorMixin, 
Executor):
             _immutable_ = True
             c_stubcall  = staticmethod(stub)
-        class BasicRefExecutor(ffitypes.typeid(c_type), 
NumericRefExecutorMixin, FunctionExecutor):
+        class BasicRefExecutor(ffitypes.typeid(c_type), 
NumericRefExecutorMixin, Executor):
             def cffi_type(self, space):
                 state = space.fromcache(ffitypes.State)
                 return state.c_voidp
diff --git a/pypy/module/_cppyy/ffitypes.py b/pypy/module/_cppyy/ffitypes.py
--- a/pypy/module/_cppyy/ffitypes.py
+++ b/pypy/module/_cppyy/ffitypes.py
@@ -74,18 +74,52 @@
         # 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 < -128 or 127 < ival:
+                raise oefmt(space.w_ValueError, "char arg not in 
range(-128,128)")
+
+            value = rffi.cast(rffi.CHAR, space.c_int_w(w_value))
+        else:
+            if space.isinstance_w(w_value, space.w_text):
+                value = space.text_w(w_value)
+            else:
+                value = space.bytes_w(w_value)
+            if len(value) != 1:
+                raise oefmt(space.w_ValueError,
+                            "char expected, got string of size %d", len(value))
+
+        value = rffi.cast(rffi.CHAR, value[0])
+        return value     # turn it into a "char" to the annotator
+
+    def cffi_type(self, space):
+        state = space.fromcache(State)
+        return state.c_char
+
+class UCharTypeMixin(object):
+    _mixin_     = True
+    _immutable_fields_ = ['c_type', 'c_ptrtype']
+
+    c_type      = rffi.UCHAR
+    c_ptrtype   = rffi.CCHARP           # there's no such thing as rffi.UCHARP
+
+    def _wrap_object(self, space, obj):
+        return space.newbytes(obj)
+
+    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 oefmt(space.w_ValueError, "char arg not in range(256)")
 
             value = rffi.cast(rffi.CHAR, space.c_int_w(w_value))
-        elif space.isinstance_w(w_value, space.w_text):
-            value = space.text_w(w_value)
         else:
-            value = space.bytes_w(w_value)
-
-        if len(value) != 1:  
-            raise oefmt(space.w_ValueError,
-                        "char expected, got string of size %d", len(value))
+            if space.isinstance_w(w_value, space.w_text):
+                value = space.text_w(w_value)
+            else:
+                value = space.bytes_w(w_value)
+            if len(value) != 1:
+                raise oefmt(space.w_ValueError,
+                            "unsigned char expected, got string of size %d", 
len(value))
 
         value = rffi.cast(rffi.CHAR, value[0])
         return value     # turn it into a "char" to the annotator
@@ -280,6 +314,7 @@
     "NOT_RPYTHON"
     if c_type == bool:            return BoolTypeMixin
     if c_type == rffi.CHAR:       return CharTypeMixin
+    if c_type == rffi.UCHAR:      return UCharTypeMixin
     if c_type == rffi.SHORT:      return ShortTypeMixin
     if c_type == rffi.USHORT:     return UShortTypeMixin
     if c_type == rffi.INT:        return IntTypeMixin
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
@@ -1,3 +1,4 @@
+import sys
 from rpython.rlib import rstring
 
 
@@ -116,6 +117,17 @@
     # TODO: perhaps absorb or "pythonify" these operators?
     return cppname
 
+if sys.hexversion < 0x3000000:
+    CPPYY__div__  = "__div__"
+    CPPYY__idiv__ = "__idiv__"
+    CPPYY__long__ = "__long__"
+    CPPYY__bool__ = "__nonzero__"
+else:
+    CPPYY__div__  = "__truediv__"
+    CPPYY__idiv__ = "__itruediv__"
+    CPPYY__long__ = "__int__"
+    CPPYY__bool__ = "__bool__"
+
 # _operator_mappings["[]"]  = "__setitem__"      # depends on return type
 # _operator_mappings["+"]   = "__add__"          # depends on # of args (see 
__pos__)
 # _operator_mappings["-"]   = "__sub__"          # id. (eq. __neg__)
@@ -123,7 +135,7 @@
 
 # _operator_mappings["[]"]  = "__getitem__"      # depends on return type
 _operator_mappings["()"]  = "__call__"
-_operator_mappings["/"]   = "__div__"            # __truediv__ in p3
+_operator_mappings["/"]   = CPPYY__div__
 _operator_mappings["%"]   = "__mod__"
 _operator_mappings["**"]  = "__pow__"            # not C++
 _operator_mappings["<<"]  = "__lshift__"
@@ -136,7 +148,7 @@
 _operator_mappings["+="]  = "__iadd__"
 _operator_mappings["-="]  = "__isub__"
 _operator_mappings["*="]  = "__imul__"
-_operator_mappings["/="]  = "__idiv__"           # __itruediv__ in p3
+_operator_mappings["/="]  = CPPYY__idiv__
 _operator_mappings["%="]  = "__imod__"
 _operator_mappings["**="] = "__ipow__"
 _operator_mappings["<<="] = "__ilshift__"
@@ -154,7 +166,7 @@
 # the following type mappings are "exact"
 _operator_mappings["const char*"] = "__str__"
 _operator_mappings["int"]         = "__int__"
-_operator_mappings["long"]        = "__long__"   # __int__ in p3
+_operator_mappings["long"]        = CPPYY__long__
 _operator_mappings["double"]      = "__float__"
 
 # the following type mappings are "okay"; the assumption is that they
@@ -163,13 +175,13 @@
 _operator_mappings["char*"]              = "__str__"
 _operator_mappings["short"]              = "__int__"
 _operator_mappings["unsigned short"]     = "__int__"
-_operator_mappings["unsigned int"]       = "__long__"      # __int__ in p3
-_operator_mappings["unsigned long"]      = "__long__"      # id.
-_operator_mappings["long long"]          = "__long__"      # id.
-_operator_mappings["unsigned long long"] = "__long__"      # id.
+_operator_mappings["unsigned int"]       = CPPYY__long__
+_operator_mappings["unsigned long"]      = CPPYY__long__
+_operator_mappings["long long"]          = CPPYY__long__
+_operator_mappings["unsigned long long"] = CPPYY__long__
 _operator_mappings["float"]              = "__float__"
 
-_operator_mappings["bool"] = "__nonzero__"       # __bool__ in p3
+_operator_mappings["bool"] = CPPYY__bool__
 
 # the following are not python, but useful to expose
 _operator_mappings["->"]  = "__follow__"
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
@@ -76,9 +76,7 @@
     cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, 
int nargs, void* args, cppyy_type_t result_type);
 
     RPY_EXTERN
-    cppyy_funcaddr_t cppyy_function_address_from_index(cppyy_scope_t scope, 
cppyy_index_t idx);
-    RPY_EXTERN
-    cppyy_funcaddr_t cppyy_function_address_from_method(cppyy_method_t method);
+    cppyy_funcaddr_t cppyy_function_address(cppyy_method_t method);
 
     /* handling of function argument buffer 
----------------------------------- */
     RPY_EXTERN
@@ -132,23 +130,28 @@
     cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const 
char* name);
 
     RPY_EXTERN
-    char* cppyy_method_name(cppyy_scope_t scope, cppyy_index_t idx);
+    cppyy_method_t cppyy_get_method(cppyy_scope_t scope, cppyy_index_t idx);
+
     RPY_EXTERN
-    char* cppyy_method_mangled_name(cppyy_scope_t scope, cppyy_index_t idx);
+    char* cppyy_method_name(cppyy_method_t);
     RPY_EXTERN
-    char* cppyy_method_result_type(cppyy_scope_t scope, cppyy_index_t idx);
+    char* cppyy_method_full_name(cppyy_method_t);
     RPY_EXTERN
-    int cppyy_method_num_args(cppyy_scope_t scope, cppyy_index_t idx);
+    char* cppyy_method_mangled_name(cppyy_method_t);
     RPY_EXTERN
-    int cppyy_method_req_args(cppyy_scope_t scope, cppyy_index_t idx);
+    char* cppyy_method_result_type(cppyy_method_t);
     RPY_EXTERN
-    char* cppyy_method_arg_type(cppyy_scope_t scope, cppyy_index_t idx, int 
arg_index);
+    int cppyy_method_num_args(cppyy_method_t);
     RPY_EXTERN
-    char* cppyy_method_arg_default(cppyy_scope_t scope, cppyy_index_t idx, int 
arg_index);
+    int cppyy_method_req_args(cppyy_method_t);
     RPY_EXTERN
-    char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx, int 
show_formalargs);
+    char* cppyy_method_arg_type(cppyy_method_t, int arg_index);
     RPY_EXTERN
-    char* cppyy_method_prototype(cppyy_scope_t scope, cppyy_index_t idx, int 
show_formalargs);
+    char* cppyy_method_arg_default(cppyy_method_t, int arg_index);
+    RPY_EXTERN
+    char* cppyy_method_signature(cppyy_method_t, int show_formalargs);
+    RPY_EXTERN
+    char* cppyy_method_prototype(cppyy_scope_t scope, cppyy_method_t idx, int 
show_formalargs);
     RPY_EXTERN
     int cppyy_is_const_method(cppyy_method_t);
 
@@ -157,25 +160,21 @@
     RPY_EXTERN
     int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx);
     RPY_EXTERN
-    int cppyy_method_num_template_args(cppyy_scope_t scope, cppyy_index_t idx);
-    RPY_EXTERN
-    char* cppyy_method_template_arg_name(cppyy_scope_t scope, cppyy_index_t 
idx, cppyy_index_t iarg);
+    cppyy_method_t cppyy_get_method_template(cppyy_scope_t scope, const char* 
name, const char* proto);
 
     RPY_EXTERN
-    cppyy_method_t cppyy_get_method(cppyy_scope_t scope, cppyy_index_t idx);
-    RPY_EXTERN
     cppyy_index_t cppyy_get_global_operator(
         cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* 
op);
 
     /* method properties 
------------------------------------------------------ */
     RPY_EXTERN
-    int cppyy_is_publicmethod(cppyy_type_t type, cppyy_index_t idx);
+    int cppyy_is_publicmethod(cppyy_method_t);
     RPY_EXTERN
-    int cppyy_is_constructor(cppyy_type_t type, cppyy_index_t idx);
+    int cppyy_is_constructor(cppyy_method_t);
     RPY_EXTERN
-    int cppyy_is_destructor(cppyy_type_t type, cppyy_index_t idx);
+    int cppyy_is_destructor(cppyy_method_t);
     RPY_EXTERN
-    int cppyy_is_staticmethod(cppyy_type_t type, cppyy_index_t idx);
+    int cppyy_is_staticmethod(cppyy_method_t);
 
     /* data member reflection information 
------------------------------------- */
     RPY_EXTERN
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
@@ -14,13 +14,21 @@
 from pypy.module._cffi_backend import ctypefunc
 from pypy.module._cppyy import converter, executor, ffitypes, helper
 
+CLASS_FLAGS_IS_PINNED      = 0x0001
 
 INSTANCE_FLAGS_PYTHON_OWNS = 0x0001
 INSTANCE_FLAGS_IS_REF      = 0x0002
-INSTANCE_FLAGS_IS_R_VALUE  = 0x0004
+INSTANCE_FLAGS_IS_RVALUE   = 0x0004
 
 OVERLOAD_FLAGS_USE_FFI     = 0x0001
 
+FUNCTION_IS_GLOBAL         = 0x0001
+FUNCTION_IS_STATIC         = 0x0001
+FUNCTION_IS_METHOD         = 0x0002
+FUNCTION_IS_CONSTRUCTOR    = 0x0004
+FUNCTION_IS_TEMPLATE       = 0x0008
+FUNCTION_IS_SETITEM        = 0x0010
+
 
 class FastCallNotPossible(Exception):
     pass
@@ -100,9 +108,9 @@
         state.cppscope_cache[final_scoped_name] = cppscope
 
         if not isns:
-            # build methods/data; TODO: also defer this for classes (a 
functional __dir__
+            # build overloads/data; TODO: also defer this for classes (a 
functional __dir__
             # and instrospection for help() is enough and allows more lazy 
loading)
-            cppscope._build_methods()
+            cppscope._build_overloads()
             cppscope._find_datamembers()
 
         return cppscope
@@ -131,7 +139,7 @@
     cppclass = space.interp_w(W_CPPClassDecl, w_cppclass)
     # add back-end specific method pythonizations (doing this on the wrapped
     # class allows simple aliasing of methods)
-    capi.pythonize(space, cppclass.name, w_pycppclass)
+    capi.pythonize(space, w_pycppclass, cppclass.name)
     state = space.fromcache(State)
     state.cppclass_registry[rffi.cast(rffi.LONG, cppclass.handle)] = 
w_pycppclass
 
@@ -150,17 +158,18 @@
 
 
 #-----
-# Classes involved with methods and functions:
+# Classes involved with methods and functions come at two levels:
+#   - overloads: user-facing collections of overloaded functions
+#   - wrappers: internal holders of the individual C++ methods
 #
-#  CPPMethod:         base class wrapping a single function or method
-#  CPPConstructor:    specialization for allocating a new object
-#  CPPFunction:       specialization for free and static functions
+#  W_CPPOverload:                 instance methods (base class)
+#  W_CPPConstructorOverload:      constructors
+#  W_CPPStaticOverload:           free and static functions
+#  W_CPPTemplateOverload:         templated methods
+#  W_CPPTemplateStaticOveload:    templated free and static functions
+#
+#  CPPMethod:         a single function or method (base class)
 #  CPPSetItem:        specialization for Python's __setitem__
-#  CPPTemplatedCall:  trampoline to instantiate and bind templated functions
-#  W_CPPOverload, W_CPPConstructorOverload, W_CPPTemplateOverload:
-#     user-facing, app-level, collection of overloads, with specializations
-#     for constructors and templates
-#  W_CPPBoundMethod:  instantiated template method
 #
 # All methods/functions derive from CPPMethod and are collected as overload
 # candidates in user-facing overload classes. Templated methods are a two-step
@@ -173,15 +182,15 @@
     also takes care of offset casting and recycling of known objects through
     the memory_regulator."""
 
-    _attrs_ = ['space', 'scope', 'index', 'cppmethod', 'arg_defs', 
'args_required',
+    _attrs_ = ['space', 'scope', 'cppmethod', 'arg_defs', 'args_required',
                'converters', 'executor', '_funcaddr', 'cif_descr', 
'uses_local']
-    _immutable_ = True
+    _immutable_fields_ = ['scope', 'cppmethod', 'arg_defs', 'args_required',
+                          'converters', 'executor', 'uses_local']
 
-    def __init__(self, space, declaring_scope, method_index, arg_defs, 
args_required):
+    def __init__(self, space, declaring_scope, cppmethod, arg_defs, 
args_required):
         self.space = space
         self.scope = declaring_scope
-        self.index = method_index
-        self.cppmethod = capi.c_get_method(self.space, self.scope, 
method_index)
+        self.cppmethod = cppmethod
         self.arg_defs = arg_defs
         self.args_required = args_required
 
@@ -193,12 +202,6 @@
         self._funcaddr = lltype.nullptr(capi.C_FUNC_PTR.TO)
         self.uses_local = False
 
-    @staticmethod
-    def unpack_cppthis(space, w_cppinstance, declaring_scope):
-        cppinstance = space.interp_w(W_CPPInstance, w_cppinstance)
-        cppinstance._nullcheck()
-        return cppinstance.get_cppthis(declaring_scope)
-
     def _address_from_local_buffer(self, call_local, idx):
         if not call_local:
             return call_local
@@ -266,11 +269,12 @@
     def do_fast_call(self, cppthis, args_w, call_local):
         if self.cif_descr == lltype.nullptr(jit_libffi.CIF_DESCRIPTION):
             raise FastCallNotPossible
+        jit.promote(self)
         cif_descr = self.cif_descr
         buffer = lltype.malloc(rffi.CCHARP.TO, cif_descr.exchange_size, 
flavor='raw')
         try:
             # this pointer
-            data = capi.exchange_address(buffer, cif_descr, 0)
+            data = rffi.ptradd(buffer, cif_descr.exchange_args[0])
             x = rffi.cast(rffi.LONGP, data)       # LONGP needed for 
test_zjit.py
             x[0] = rffi.cast(rffi.LONG, cppthis)
 
@@ -279,11 +283,11 @@
             for i in range(len(args_w)):
                 conv = self.converters[i]
                 w_arg = args_w[i]
-                data = capi.exchange_address(buffer, cif_descr, i+1)
+                data = rffi.ptradd(buffer, cif_descr.exchange_args[i+1])
                 conv.convert_argument_libffi(self.space, w_arg, data, 
call_local)
             for j in range(i+1, len(self.arg_defs)):
                 conv = self.converters[j]
-                data = capi.exchange_address(buffer, cif_descr, j+1)
+                data = rffi.ptradd(buffer, cif_descr.exchange_args[j+1])
                 conv.default_argument_libffi(self.space, data)
 
             assert self._funcaddr
@@ -295,7 +299,7 @@
         return w_res
 
     # from ctypefunc; have my own version for annotater purposes and to disable
-    # memory tracking (method live time is longer than the tests)
+    # memory tracking (method life time is longer than the tests)
     @jit.dont_look_inside
     def _rawallocate(self, builder):
         builder.space = self.space
@@ -308,7 +312,7 @@
         # allocate the buffer
         if we_are_translated():
             rawmem = lltype.malloc(rffi.CCHARP.TO, builder.nb_bytes,
-                                   flavor='raw', track_allocation=False)
+                                   flavor='raw')
             rawmem = rffi.cast(jit_libffi.CIF_DESCRIPTION_P, rawmem)
         else:
             # gross overestimation of the length below, but too bad
@@ -340,7 +344,7 @@
         self.converters = [converter.get_converter(self.space, arg_type, 
arg_dflt)
                                for arg_type, arg_dflt in self.arg_defs]
         self.executor = executor.get_executor(
-            self.space, capi.c_method_result_type(self.space, self.scope, 
self.index))
+            self.space, capi.c_method_result_type(self.space, self.cppmethod))
 
         for conv in self.converters:
             if conv.uses_local:
@@ -350,8 +354,8 @@
         # Each CPPMethod corresponds one-to-one to a C++ equivalent and cppthis
         # has been offset to the matching class. Hence, the libffi pointer is
         # uniquely defined and needs to be setup only once.
-        funcaddr = capi.c_function_address_from_index(self.space, self.scope, 
self.index)
-        if funcaddr and cppthis:      # methods only for now
+        funcaddr = capi.c_function_address(self.space, self.cppmethod)
+        if funcaddr and cppthis:      # TODO: methods only for now
             state = self.space.fromcache(ffitypes.State)
 
             # argument type specification (incl. cppthis)
@@ -418,10 +422,10 @@
         capi.c_deallocate_function_args(self.space, args)
 
     def signature(self, show_formalargs=True):
-        return capi.c_method_signature(self.space, self.scope, self.index, 
show_formalargs)
+        return capi.c_method_signature(self.space, self.cppmethod, 
show_formalargs)
 
     def prototype(self, show_formalargs=True):
-        return capi.c_method_prototype(self.space, self.scope, self.index, 
show_formalargs)
+        return capi.c_method_prototype(self.space, self.scope, self.cppmethod, 
show_formalargs)
 
     def priority(self):
         total_arg_priority = 0
@@ -431,8 +435,11 @@
 
     @rgc.must_be_light_finalizer
     def __del__(self):
-        if self.cif_descr:
-            lltype.free(self.cif_descr, flavor='raw')
+        try:
+            if self.cif_descr:
+                lltype.free(self.cif_descr, flavor='raw')
+        except Exception:     # TODO: happens for templates, why?
+            pass
 
     def __repr__(self):
         return "CPPMethod: %s" % self.prototype()
@@ -441,80 +448,12 @@
         assert 0, "you should never have a pre-built instance of this!"
 
 
-class CPPFunction(CPPMethod):
-    """Global (namespaced) / static function dispatcher."""
-
-    _immutable_ = True
-
-    @staticmethod
-    def unpack_cppthis(space, w_cppinstance, declaring_scope):
-        return capi.C_NULL_OBJECT
-
-    def __repr__(self):
-        return "CPPFunction: %s" % self.prototype()
-
-
-class CPPTemplatedCall(CPPMethod):
-    """Method dispatcher that first resolves the template instance."""
-
-    _attrs_ = ['space', 'templ_args']
-    _immutable_ = True
-
-    def __init__(self, space, templ_args, declaring_scope, method_index, 
arg_defs, args_required):
-        self.space = space
-        self.templ_args = templ_args
-        # TODO: might have to specialize for CPPTemplatedCall on 
CPPMethod/CPPFunction here
-        CPPMethod.__init__(self, space, declaring_scope, method_index, 
arg_defs, args_required)
-
-    def call(self, cppthis, args_w, useffi):
-        assert lltype.typeOf(cppthis) == capi.C_OBJECT
-        for i in range(len(args_w)):
-            try:
-                s = self.space.text_w(args_w[i])
-            except OperationError:
-                s = self.space.text_w(self.space.getattr(args_w[i], 
self.space.newtext('__name__')))
-            s = capi.c_resolve_name(self.space, s)
-            if s != self.templ_args[i]:
-                raise oefmt(self.space.w_TypeError,
-                            "non-matching template (got %s where %s expected)",
-                            s, self.templ_args[i])
-        return W_CPPBoundMethod(cppthis, self, useffi)
-
-    def bound_call(self, cppthis, args_w, useffi):
-        return CPPMethod.call(self, cppthis, args_w, useffi)
-
-    def __repr__(self):
-        return "CPPTemplatedCall: %s" % self.prototype()
-
-
-class CPPConstructor(CPPMethod):
-    """Method dispatcher that constructs new objects. This method can not have
-    a fast path, as the allocation of the object is currently left to the
-    reflection layer only, since the C++ class may have an overloaded operator
-    new, disallowing malloc here."""
-
-    _immutable_ = True
-
-    @staticmethod
-    def unpack_cppthis(space, w_cppinstance, declaring_scope):
-        return rffi.cast(capi.C_OBJECT, declaring_scope.handle)
-
-    def call(self, cppthis, args_w, useffi):
-        # Note: this does not return a wrapped instance, just a pointer to the
-        # new instance; the overload must still wrap it before returning. Also,
-        # cppthis is declaring_scope.handle (as per unpack_cppthis(), above).
-        return CPPMethod.call(self, cppthis, args_w, useffi)
-
-    def __repr__(self):
-        return "CPPConstructor: %s" % self.prototype()
-
-
 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
+    _attrs_ = []
 
     def call(self, cppthis, args_w, useffi):
         end = len(args_w)-1
@@ -528,46 +467,44 @@
 
 
 class W_CPPOverload(W_Root):
-    """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."""
+    """App-level dispatcher: controls a collection of (potentially) overloaded 
methods
+    or functions. Calls these in order and deals with error handling and 
reporting."""
 
-    _attrs_ = ['space', 'scope', 'functions', 'flags']
+    _attrs_ = ['space', 'scope', 'functions', 'flags', 'w_this']
     _immutable_fields_ = ['scope', 'functions[*]']
 
-    def __init__(self, space, declaring_scope, functions):
-        self.space = space
-        self.scope = declaring_scope
-        assert len(functions)
+    def __init__(self, space, declaring_scope, functions, flags = 
OVERLOAD_FLAGS_USE_FFI):
+        self.space  = space
+        self.scope  = declaring_scope
         from rpython.rlib import debug
         self.functions = debug.make_sure_not_resized(functions)
-        self.flags = 0
-        self.flags |= OVERLOAD_FLAGS_USE_FFI
+        self.flags  = flags
+        self.w_this = self.space.w_None
 
-    # allow user to determine ffi use rules per overload
-    def fget_useffi(self, space):
-        return space.newbool(bool(self.flags & OVERLOAD_FLAGS_USE_FFI))
+    @unwrap_spec(args_w='args_w')
+    def descr_get(self, w_cppinstance, args_w):
+        if self.space.is_w(w_cppinstance, self.space.w_None):
+            return self  # unbound, so no new instance needed
+        cppol = W_CPPOverload(self.space, self.scope, self.functions, 
self.flags)
+        cppol.w_this = w_cppinstance
+        return cppol     # bound
 
-    @unwrap_spec(value=bool)
-    def fset_useffi(self, space, value):
-        if space.is_true(value):
-            self.flags |= OVERLOAD_FLAGS_USE_FFI
+    @unwrap_spec(args_w='args_w')
+    def call(self, args_w):
+        if self.space.is_w(self.w_this, self.space.w_None) and len(args_w):
+            w_this = args_w[0]
+            args_w = args_w[1:]
         else:
-            self.flags &= ~OVERLOAD_FLAGS_USE_FFI
-
-    @jit.elidable_promote()
-    def is_static(self):
-        if isinstance(self.functions[0], CPPFunction):
-            return self.space.w_True
-        return self.space.w_False
+            w_this = self.w_this
+        cppinstance = self.space.interp_w(W_CPPInstance, w_this)
+        cppinstance._nullcheck()
+        if not capi.c_is_subtype(self.space, cppinstance.clsdecl, self.scope):
+            raise oefmt(self.space.w_TypeError,
+                "cannot pass %T instance as %s", w_this, self.scope.name)
+        return self.call_impl(cppinstance.get_cppthis(self.scope), args_w)
 
     @jit.unroll_safe
-    @unwrap_spec(args_w='args_w')
-    def call(self, w_cppinstance, args_w):
-        # instance handling is specific to the function type only, so take it 
out
-        # of the loop over function overloads
-        cppthis = self.functions[0].unpack_cppthis(
-            self.space, w_cppinstance, self.functions[0].scope)
+    def call_impl(self, cppthis, args_w):
         assert lltype.typeOf(cppthis) == capi.C_OBJECT
 
         # The following code tries out each of the functions in order. If
@@ -625,38 +562,96 @@
             sig += '\n'+self.functions[i].prototype()
         return self.space.newtext(sig)
 
+    # allow user to determine ffi use rules per overload
+    def fget_useffi(self, space):
+        return space.newbool(bool(self.flags & OVERLOAD_FLAGS_USE_FFI))
+
+    @unwrap_spec(value=bool)
+    def fset_useffi(self, space, value):
+        if space.is_true(value):
+            self.flags |= OVERLOAD_FLAGS_USE_FFI
+        else:
+            self.flags &= ~OVERLOAD_FLAGS_USE_FFI
+
+    def fget_doc(self, space):
+        return self.prototype()
+
     def __repr__(self):
         return "W_CPPOverload(%s)" % [f.prototype() for f in self.functions]
 
 W_CPPOverload.typedef = TypeDef(
     'CPPOverload',
-    is_static = interp2app(W_CPPOverload.is_static),
-    call = interp2app(W_CPPOverload.call),
+    __get__    = interp2app(W_CPPOverload.descr_get),
+    __call__   = interp2app(W_CPPOverload.call),
     __useffi__ = GetSetProperty(W_CPPOverload.fget_useffi, 
W_CPPOverload.fset_useffi),
-    prototype = interp2app(W_CPPOverload.prototype),
+    __doc__    = GetSetProperty(W_CPPOverload.fget_doc)
 )
 
 
+# overload collection of static (class and free) functions; these differ
+# from methods only in the handling of 'cppthis'
+class W_CPPStaticOverload(W_CPPOverload):
+    _attrs_ = []
+
+    @unwrap_spec(args_w='args_w')
+    def descr_get(self, w_cppinstance, args_w):
+        if isinstance(w_cppinstance, W_CPPInstance):
+            # two possibilities: this is a static function called on an
+            # instance and w_this must not be set, or a free function rebound
+            # onto a class and w_this should be set
+            cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance)
+            if cppinstance.clsdecl.handle != self.scope.handle:
+                cppol = W_CPPStaticOverload(self.space, self.scope, 
self.functions, self.flags)
+                cppol.w_this = w_cppinstance
+                return cppol       # bound
+        return self      # unbound
+
+    @unwrap_spec(args_w='args_w')
+    def call(self, args_w):
+        if not self.space.is_w(self.w_this, self.space.w_None):
+            # free function used as bound method, put self back into args_w
+            cppinstance = self.space.interp_w(W_CPPInstance, self.w_this)
+            cppinstance._nullcheck()
+            args_w = [self.w_this] + args_w
+        return self.call_impl(capi.C_NULL_OBJECT, args_w)
+
+    def __repr__(self):
+        return "W_CPPStaticOverload(%s)" % [f.prototype() for f in 
self.functions]
+
+W_CPPStaticOverload.typedef = TypeDef(
+    'CPPStaticOverload',
+    __get__    = interp2app(W_CPPStaticOverload.descr_get),
+    __call__   = interp2app(W_CPPStaticOverload.call),
+    __useffi__ = GetSetProperty(W_CPPStaticOverload.fget_useffi, 
W_CPPStaticOverload.fset_useffi),
+    __doc__    = GetSetProperty(W_CPPStaticOverload.fget_doc)
+)
+
+
 class W_CPPConstructorOverload(W_CPPOverload):
-    @jit.elidable_promote()
-    def is_static(self):
-        return self.space.w_False
+    _attrs_ = []
 
-    @jit.elidable_promote()
-    def unpack_cppthis(self, w_cppinstance):
-        return rffi.cast(capi.C_OBJECT, self.scope.handle)
+    @unwrap_spec(args_w='args_w')
+    def descr_get(self, w_cppinstance, args_w):
+        if self.space.is_w(w_cppinstance, self.space.w_None):
+            return self  # unbound (TODO: probably useless)
+        cppol = W_CPPConstructorOverload(self.space, self.scope, 
self.functions, self.flags)
+        cppol.w_this = w_cppinstance
+        return cppol     # bound
 
-    @jit.unroll_safe
     @unwrap_spec(args_w='args_w')
-    def call(self, w_cppinstance, args_w):
+    def call(self, args_w):
         # TODO: factor out the following:
         if capi.c_is_abstract(self.space, self.scope.handle):
             raise oefmt(self.space.w_TypeError,
                         "cannot instantiate abstract class '%s'",
                         self.scope.name)
-        w_result = W_CPPOverload.call(self, w_cppinstance, args_w)
+        if self.space.is_w(self.w_this, self.space.w_None) and len(args_w):
+            cppinstance = self.space.interp_w(W_CPPInstance, args_w[0])
+            args_w = args_w[1:]
+        else:
+            cppinstance = self.space.interp_w(W_CPPInstance, self.w_this)
+        w_result = self.call_impl(rffi.cast(capi.C_OBJECT, self.scope.handle), 
args_w)
         newthis = rffi.cast(capi.C_OBJECT, self.space.uint_w(w_result))
-        cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, 
can_be_None=True)
         if cppinstance is not None:
             cppinstance._rawobject = newthis
             memory_regulator.register(cppinstance)
@@ -666,43 +661,224 @@
 
 W_CPPConstructorOverload.typedef = TypeDef(
     'CPPConstructorOverload',
-    is_static = interp2app(W_CPPConstructorOverload.is_static),
-    call = interp2app(W_CPPConstructorOverload.call),
-    prototype = interp2app(W_CPPConstructorOverload.prototype),
+    __get__    = interp2app(W_CPPConstructorOverload.descr_get),
+    __call__   = interp2app(W_CPPConstructorOverload.call),
+    __doc__    = GetSetProperty(W_CPPConstructorOverload.fget_doc)
 )
 
 
-class W_CPPTemplateOverload(W_CPPOverload):
+class TemplateOverloadMixin(object):
+    """Mixin to instantiate templated methods/functions."""
+
+    _mixin_ = True
+
+    def construct_template_args(self, w_tpArgs, args_w = None):
+        space = self.space
+        tmpl_args = ''
+        for i in range(space.len_w(w_tpArgs)):
+            w_tp = space.getitem(w_tpArgs, space.newint(i))
+            if space.isinstance_w(w_tp, space.w_text):
+                s = space.text_w(w_tp)      # string describing type
+            elif space.isinstance_w(w_tp, space.w_type):
+                try:
+                    # cppyy bound types
+                    s = space.text_w(space.getattr(w_tp, 
space.newtext('__cppname__')))
+                    if args_w:
+                        # try to specialize the type match for the given object
+                        cppinstance = self.space.interp_w(W_CPPInstance, 
args_w[i])
+                        if cppinstance.flags & INSTANCE_FLAGS_IS_RVALUE:
+                            sugar = "&&"
+                        elif cppinstance.flags & INSTANCE_FLAGS_IS_REF:
+                            sugar = "*"
+                        else:
+                            sugar = "&"
+                        s += sugar
+                except OperationError:
+                    # generic python types
+                    s = space.text_w(space.getattr(w_tp, 
space.newtext('__name__')))
+            else:
+                # builtin types etc.
+                s = space.text_w(space.str(w_tp))
+            # map python types -> C++ types
+            if s == 'str': s = 'std::string'
+            if i != 0: tmpl_args += ', '
+            tmpl_args += s
+        return tmpl_args
+
+    def find_method_template(self, name, proto = ''):
+        # find/instantiate new callable function
+        space = self.space
+        cppmeth = capi.c_get_method_template(space, self.scope, name, proto)
+        if not cppmeth:
+            raise oefmt(self.space.w_AttributeError,
+                "scope '%s' has no function %s", self.scope.name, name)
+
+        funcs = []
+        ftype = self.scope._make_cppfunction(name, cppmeth, funcs)
+        if ftype & FUNCTION_IS_STATIC:
+            cppol = W_CPPStaticOverload(space, self.scope, funcs[:], 
self.flags)
+        else:
+            cppol = W_CPPOverload(space, self.scope, funcs[:], self.flags)
+        return cppol
+
+    def instantiate_and_call(self, name, args_w):
+        # try to match with run-time instantiations
+        for cppol in self.master.overloads.values():
+            try:
+                return cppol.descr_get(self.w_this, []).call(args_w)
+            except Exception:
+                pass    # completely ignore for now; have to see whether 
errors become confusing
+
+        # if all failed, then try to deduce from argument types
+        w_types = self.space.newtuple([self.space.type(obj_w) for obj_w in 
args_w])
+        proto = self.construct_template_args(w_types, args_w)
+        method = self.find_method_template(name, proto)
+
+        # only cache result if the name retains the full template
+        fullname = capi.c_method_full_name(self.space, 
method.functions[0].cppmethod)
+        if 0 <= fullname.rfind('>'):
+            try:
+                existing = self.master.overloads[fullname]
+                allf = existing.functions + method.functions
+                if isinstance(existing, W_CPPStaticOverload):
+                    cppol = W_CPPStaticOverload(self.space, self.scope, allf, 
self.flags)
+                else:
+                    cppol = W_CPPOverload(self.space, self.scope, allf, 
self.flags)
+                self.master.overloads[fullname] = cppol
+            except KeyError:
+                self.master.overloads[fullname] = method
+
+        return method.descr_get(self.w_this, []).call(args_w)
+
+    def getitem_impl(self, name, args_w):
+        space = self.space
+
+        if space.isinstance_w(args_w[0], space.w_tuple):
+            w_args = args_w[0]
+        else:
+            w_args = space.newtuple(args_w)
+
+        tmpl_args = self.construct_template_args(w_args)
+        fullname = name+'<'+tmpl_args+'>'
+        try:
+            method = self.master.overloads[fullname]
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to