[pypy-commit] pypy py3.6: hg merge py3.5

rlamy pypy.commits at gmail.com
Fri Jul 27 21:01:33 EDT 2018


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: py3.6
Changeset: r94909:ebe135031f7e
Date: 2018-07-28 02:00 +0100
http://bitbucket.org/pypy/pypy/changeset/ebe135031f7e/

Log:	hg merge py3.5

diff too long, truncating to 2000 out of 4128 lines

diff --git a/lib-python/3/fractions.py b/lib-python/3/fractions.py
--- a/lib-python/3/fractions.py
+++ b/lib-python/3/fractions.py
@@ -542,7 +542,7 @@
         else:
             return Fraction(round(self / shift) * shift)
 
-    def __hash__(self):
+    def __hash__(self, CACHE=[-1] * 1001):
         """hash(self)"""
 
         # XXX since this method is expensive, consider caching the result
@@ -556,12 +556,23 @@
         # dinv is the inverse of self._denominator modulo the prime
         # _PyHASH_MODULUS, or 0 if self._denominator is divisible by
         # _PyHASH_MODULUS.
-        dinv = pow(self._denominator, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
+
+        # PyPy3: added caching of pow() results for denominators up to 1000
+        denom = self._denominator
+        assert denom >= 0
+        if denom < len(CACHE):
+            dinv = CACHE[denom]
+            if dinv == -1:
+                dinv = pow(denom, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
+                CACHE[denom] = dinv
+        else:
+            dinv = pow(denom, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
+
         if not dinv:
             hash_ = _PyHASH_INF
         else:
             hash_ = abs(self._numerator) * dinv % _PyHASH_MODULUS
-        result = hash_ if self >= 0 else -hash_
+        result = hash_ if self._numerator >= 0 else -hash_
         return -2 if result == -1 else result
 
     def __eq__(a, b):
diff --git a/lib-python/3/hashlib.py b/lib-python/3/hashlib.py
--- a/lib-python/3/hashlib.py
+++ b/lib-python/3/hashlib.py
@@ -162,9 +162,14 @@
     __get_hash = __get_openssl_constructor
     algorithms_available = algorithms_available.union(
             _hashlib.openssl_md_meth_names)
-except ImportError:
+except ImportError as e:
     new = __py_new
     __get_hash = __get_builtin_constructor
+    # added by PyPy
+    import warnings
+    warnings.warn("The _hashlib module is not available, falling back "
+                  "to a much slower implementation (%s)" % str(e),
+                  RuntimeWarning)
 
 try:
     # OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA
diff --git a/lib_pypy/_winapi.py b/lib_pypy/_winapi.py
--- a/lib_pypy/_winapi.py
+++ b/lib_pypy/_winapi.py
@@ -98,9 +98,11 @@
     def GetOverlappedResult(self, wait):
         transferred = _ffi.new('DWORD[1]', [0])
         res = _kernel32.GetOverlappedResult(self.handle, self.overlapped, transferred, wait != 0)
-        if not res:
-            res = GetLastError()
-        if res in (ERROR_SUCCESS, ERROR_MORE_DATA, ERROR_OPERATION_ABORTED):
+        if res:
+            err = ERROR_SUCCESS
+        else:
+            err = GetLastError()
+        if err in (ERROR_SUCCESS, ERROR_MORE_DATA, ERROR_OPERATION_ABORTED):
             self.completed = 1
             self.pending = 0
         elif res == ERROR_IO_INCOMPLETE:
@@ -133,7 +135,7 @@
         assert success == 0
         err = _kernel32.GetLastError()
         if err == ERROR_IO_PENDING:
-            overlapped[0].pending = 1
+            ov.pending = 1
         elif err == ERROR_PIPE_CONNECTED:
             _kernel32.SetEvent(ov.overlapped[0].hEvent)
         else:
diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO
--- a/lib_pypy/cffi.egg-info/PKG-INFO
+++ b/lib_pypy/cffi.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cffi
-Version: 1.11.5
+Version: 1.12.0
 Summary: Foreign Function Interface for Python calling C code.
 Home-page: http://cffi.readthedocs.org
 Author: Armin Rigo, Maciej Fijalkowski
diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py
--- a/lib_pypy/cffi/__init__.py
+++ b/lib_pypy/cffi/__init__.py
@@ -4,8 +4,8 @@
 from .api import FFI
 from .error import CDefError, FFIError, VerificationError, VerificationMissing
 
-__version__ = "1.11.5"
-__version_info__ = (1, 11, 5)
+__version__ = "1.12.0"
+__version_info__ = (1, 12, 0)
 
 # The verifier module file names are based on the CRC32 of a string that
 # contains the following version number.  It may be older than __version__
diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h
--- a/lib_pypy/cffi/_embedding.h
+++ b/lib_pypy/cffi/_embedding.h
@@ -221,7 +221,7 @@
 
         if (f != NULL && f != Py_None) {
             PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
-                               "\ncompiled with cffi version: 1.11.5"
+                               "\ncompiled with cffi version: 1.12.0"
                                "\n_cffi_backend module: ", f);
             modules = PyImport_GetModuleDict();
             mod = PyDict_GetItemString(modules, "_cffi_backend");
diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -96,18 +96,21 @@
             self.CData, self.CType = backend._get_types()
         self.buffer = backend.buffer
 
-    def cdef(self, csource, override=False, packed=False):
+    def cdef(self, csource, override=False, packed=False, pack=None):
         """Parse the given C source.  This registers all declared functions,
         types, and global variables.  The functions and global variables can
         then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'.
         The types can be used in 'ffi.new()' and other functions.
         If 'packed' is specified as True, all structs declared inside this
         cdef are packed, i.e. laid out without any field alignment at all.
+        Alternatively, 'pack' can be a small integer, and requests for
+        alignment greater than that are ignored (pack=1 is equivalent to
+        packed=True).
         """
-        self._cdef(csource, override=override, packed=packed)
+        self._cdef(csource, override=override, packed=packed, pack=pack)
 
-    def embedding_api(self, csource, packed=False):
-        self._cdef(csource, packed=packed, dllexport=True)
+    def embedding_api(self, csource, packed=False, pack=None):
+        self._cdef(csource, packed=packed, pack=pack, dllexport=True)
         if self._embedding is None:
             self._embedding = ''
 
diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py
--- a/lib_pypy/cffi/backend_ctypes.py
+++ b/lib_pypy/cffi/backend_ctypes.py
@@ -730,7 +730,8 @@
         return self._new_struct_or_union('union', name, ctypes.Union)
 
     def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp,
-                                 totalsize=-1, totalalignment=-1, sflags=0):
+                                 totalsize=-1, totalalignment=-1, sflags=0,
+                                 pack=0):
         if totalsize >= 0 or totalalignment >= 0:
             raise NotImplementedError("the ctypes backend of CFFI does not support "
                                       "structures completed by verify(); please "
@@ -751,6 +752,8 @@
                 bfield_types[fname] = Ellipsis
         if sflags & 8:
             struct_or_union._pack_ = 1
+        elif pack:
+            struct_or_union._pack_ = pack
         struct_or_union._fields_ = cfields
         CTypesStructOrUnion._bfield_types = bfield_types
         #
diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py
--- a/lib_pypy/cffi/cparser.py
+++ b/lib_pypy/cffi/cparser.py
@@ -306,11 +306,25 @@
             msg = 'parse error\n%s' % (msg,)
         raise CDefError(msg)
 
-    def parse(self, csource, override=False, packed=False, dllexport=False):
+    def parse(self, csource, override=False, packed=False, pack=None,
+                    dllexport=False):
+        if packed:
+            if packed != True:
+                raise ValueError("'packed' should be False or True; use "
+                                 "'pack' to give another value")
+            if pack:
+                raise ValueError("cannot give both 'pack' and 'packed'")
+            pack = 1
+        elif pack:
+            if pack & (pack - 1):
+                raise ValueError("'pack' must be a power of two, not %r" %
+                    (pack,))
+        else:
+            pack = 0
         prev_options = self._options
         try:
             self._options = {'override': override,
-                             'packed': packed,
+                             'packed': pack,
                              'dllexport': dllexport}
             self._internal_parse(csource)
         finally:
diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py
--- a/lib_pypy/cffi/model.py
+++ b/lib_pypy/cffi/model.py
@@ -342,7 +342,7 @@
     fixedlayout = None
     completed = 0
     partial = False
-    packed = False
+    packed = 0
 
     def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None):
         self.name = name
@@ -414,11 +414,14 @@
             fldtypes = [tp.get_cached_btype(ffi, finishlist)
                         for tp in self.fldtypes]
             lst = list(zip(self.fldnames, fldtypes, self.fldbitsize))
-            sflags = 0
+            extra_flags = ()
             if self.packed:
-                sflags = 8    # SF_PACKED
+                if self.packed == 1:
+                    extra_flags = (8,)    # SF_PACKED
+                else:
+                    extra_flags = (0, self.packed)
             ffi._backend.complete_struct_or_union(BType, lst, self,
-                                                  -1, -1, sflags)
+                                                  -1, -1, *extra_flags)
             #
         else:
             fldtypes = []
diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py
--- a/lib_pypy/cffi/recompiler.py
+++ b/lib_pypy/cffi/recompiler.py
@@ -893,6 +893,12 @@
             else:
                 flags.append("_CFFI_F_CHECK_FIELDS")
             if tp.packed:
+                if tp.packed > 1:
+                    raise NotImplementedError(
+                        "%r is declared with 'pack=%r'; only 0 or 1 are "
+                        "supported in API mode (try to use \"...;\", which "
+                        "does not require a 'pack' declaration)" %
+                        (tp, tp.packed))
                 flags.append("_CFFI_F_PACKED")
         else:
             flags.append("_CFFI_F_EXTERNAL")
diff --git a/lib_pypy/pyrepl/simple_interact.py b/lib_pypy/pyrepl/simple_interact.py
--- a/lib_pypy/pyrepl/simple_interact.py
+++ b/lib_pypy/pyrepl/simple_interact.py
@@ -66,6 +66,10 @@
 
     while 1:
         try:
+            try:
+                sys.stdout.flush()
+            except:
+                pass
             ps1 = getattr(sys, 'ps1', '>>> ')
             ps2 = getattr(sys, 'ps2', '... ')
             try:
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -43,14 +43,10 @@
     "_jitlog",
 ])
 
-from rpython.jit.backend import detect_cpu
-try:
-    if detect_cpu.autodetect().startswith('x86'):
-        if not sys.platform.startswith('openbsd'):
-            working_modules.add('_vmprof')
-            working_modules.add('faulthandler')
-except detect_cpu.ProcessorAutodetectError:
-    pass
+import rpython.rlib.rvmprof.cintf
+if rpython.rlib.rvmprof.cintf.IS_SUPPORTED:
+    working_modules.add('_vmprof')
+    working_modules.add('faulthandler')
 
 translation_modules = default_modules.copy()
 translation_modules.update([
@@ -323,3 +319,4 @@
     parser = to_optparse(config) #, useoptions=["translation.*"])
     option, args = parser.parse_args()
     print config
+    print working_modules
diff --git a/pypy/doc/config/objspace.disable_entrypoints.txt b/pypy/doc/config/objspace.disable_entrypoints.txt
new file mode 100644
diff --git a/pypy/doc/config/objspace.fstrings.txt b/pypy/doc/config/objspace.fstrings.txt
new file mode 100644
diff --git a/pypy/doc/config/objspace.hash.txt b/pypy/doc/config/objspace.hash.txt
new file mode 100644
diff --git a/pypy/doc/config/objspace.usemodules._frozen_importlib.txt b/pypy/doc/config/objspace.usemodules._frozen_importlib.txt
new file mode 100644
diff --git a/pypy/doc/config/objspace.usemodules._jitlog.txt b/pypy/doc/config/objspace.usemodules._jitlog.txt
new file mode 100644
diff --git a/pypy/doc/config/objspace.usemodules.faulthandler.txt b/pypy/doc/config/objspace.usemodules.faulthandler.txt
new file mode 100644
diff --git a/pypy/doc/config/translation.backendopt.replace_we_are_jitted.txt b/pypy/doc/config/translation.backendopt.replace_we_are_jitted.txt
new file mode 100644
diff --git a/pypy/doc/config/translation.jit_opencoder_model.txt b/pypy/doc/config/translation.jit_opencoder_model.txt
new file mode 100644
diff --git a/pypy/doc/config/translation.keepgoing.txt b/pypy/doc/config/translation.keepgoing.txt
new file mode 100644
diff --git a/pypy/doc/config/translation.libname.txt b/pypy/doc/config/translation.libname.txt
new file mode 100644
diff --git a/pypy/doc/config/translation.lto.txt b/pypy/doc/config/translation.lto.txt
new file mode 100644
diff --git a/pypy/doc/config/translation.profoptargs.txt b/pypy/doc/config/translation.profoptargs.txt
new file mode 100644
diff --git a/pypy/doc/config/translation.reverse_debugger.txt b/pypy/doc/config/translation.reverse_debugger.txt
new file mode 100644
diff --git a/pypy/doc/config/translation.split_gc_address_space.txt b/pypy/doc/config/translation.split_gc_address_space.txt
new file mode 100644
diff --git a/pypy/doc/tool/makecontributor.py b/pypy/doc/tool/makecontributor.py
--- a/pypy/doc/tool/makecontributor.py
+++ b/pypy/doc/tool/makecontributor.py
@@ -18,12 +18,13 @@
     'Antonio Cuni': ['antocuni', 'anto'],
     'Armin Rigo': ['arigo', 'arfigo', 'armin', 'arigato'],
     'Maciej Fijalkowski': ['fijal'],
-    'Carl Friedrich Bolz-Tereick': ['Carl Friedrich Bolz', 'cfbolz', 'cf'],
+    'Carl Friedrich Bolz-Tereick': ['Carl Friedrich Bolz', 'cfbolz', 'cf', 'cbolz'],
     'Samuele Pedroni': ['pedronis', 'samuele', 'samule'],
-    'Richard Plangger':['planrich'],
-    'Michael Hudson': ['mwh'],
+    'Richard Plangger': ['planrich', 'plan_rich'],
+    'Remi Meier': ['remi'],
+    'Michael Hudson-Doyle': ['mwh', 'Michael Hudson'],
     'Holger Krekel': ['hpk', 'holger krekel', 'holger', 'hufpk'],
-    "Amaury Forgeot d'Arc": ['afa'],
+    "Amaury Forgeot d'Arc": ['afa', 'amauryfa at gmail.com'],
     'Alex Gaynor': ['alex', 'agaynor'],
     'David Schneider': ['bivab', 'david'],
     'Christian Tismer': ['chris', 'christian', 'tismer',
@@ -41,7 +42,7 @@
     'Mark Pearse': ['mwp'],
     'Toon Verwaest': ['tverwaes'],
     'Eric van Riet Paap': ['ericvrp'],
-    'Jacob Hallen': ['jacob', 'jakob'],
+    'Jacob Hallen': ['jacob', 'jakob', 'jacob hallen'],
     'Anders Lehmann': ['ale', 'anders'],
     'Bert Freudenberg': ['bert'],
     'Boris Feigin': ['boris', 'boria'],
@@ -69,19 +70,25 @@
     'Manuel Jacob': ['mjacob'],
     'Rami Chowdhury': ['necaris'],
     'Stanislaw Halik': ['Stanislaw Halik', 'w31rd0'],
-    'Wenzhu Man':['wenzhu man', 'wenzhuman'],
-    'Anton Gulenko':['anton gulenko', 'anton_gulenko'],
-    'Richard Lancaster':['richardlancaster'],
-    'William Leslie':['William ML Leslie'],
-    'Spenser Bauman':['Spenser Andrew Bauman'],
-    'Raffael Tfirst':['raffael.tfirst at gmail.com'],
-    'timo':['timo at eistee.fritz.box'],
-    'Jasper Schulz':['Jasper.Schulz', 'jbs'],
-    'Aaron Gallagher':['"Aaron Gallagher'],
-    'Yasir Suhail':['yasirs'],
+    'Wenzhu Man': ['wenzhu man', 'wenzhuman'],
+    'Anton Gulenko': ['anton gulenko', 'anton_gulenko'],
+    'Richard Lancaster': ['richardlancaster'],
+    'William Leslie': ['William ML Leslie'],
+    'Spenser Bauman': ['Spenser Andrew Bauman'],
+    'Raffael Tfirst': ['raffael.tfirst at gmail.com'],
+    'timo': ['timo at eistee.fritz.box'],
+    'Jasper Schulz': ['Jasper.Schulz', 'jbs'],
+    'Aaron Gallagher': ['"Aaron Gallagher'],
+    'Yasir Suhail': ['yasirs'],
     'Squeaky': ['squeaky'],
-    "Amaury Forgeot d'Arc": ['amauryfa at gmail.com'],
     "Dodan Mihai": ['mihai.dodan at gmail.com'],
+    'Wim Lavrijsen': ['wlav'],
+    'Toon Verwaest': ['toon', 'tverwaes'],
+    'Seo Sanghyeon': ['sanxiyn'],
+    'Leonardo Santagada': ['santagada'],
+    'Laurence Tratt': ['ltratt'],
+    'Pieter Zieschang': ['pzieschang', 'p_zieschang at yahoo.de'],
+    'John Witulski': ['witulski'],
     }
 
 alias_map = {}
@@ -103,7 +110,8 @@
         return set()
     ignore_words = ['around', 'consulting', 'yesterday', 'for a bit', 'thanks',
                     'in-progress', 'bits of', 'even a little', 'floating',
-                    'a bit', 'reviewing']
+                    'a bit', 'reviewing', 'looking', 'advising', 'partly', 'ish',
+                    'watching', 'mostly', 'jumping']
     sep_words = ['and', ';', '+', '/', 'with special  by']
     nicknames = match.group(1)
     for word in ignore_words:
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,12 @@
 
 .. branch: cppyy-packaging
 
-Upgrade to backend 1.1.0, improved handling of templated methods and
+Upgrade to backend 1.2.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
+interface, range of compatibility fixes for Python3, free functions now take
+fast libffi path when possible, moves for strings (incl. from Python str),
+easier/faster handling of std::vector by numpy, improved and faster object
+identity preservation
 
 .. branch: socket_default_timeout_blockingness
 
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -48,6 +48,7 @@
         'int_lshift':      'interp_intop.int_lshift',
         'int_rshift':      'interp_intop.int_rshift',
         'uint_rshift':     'interp_intop.uint_rshift',
+        'int_mulmod':      'interp_intop.int_mulmod',
     }
 
 
diff --git a/pypy/module/__pypy__/interp_intop.py b/pypy/module/__pypy__/interp_intop.py
--- a/pypy/module/__pypy__/interp_intop.py
+++ b/pypy/module/__pypy__/interp_intop.py
@@ -2,7 +2,7 @@
 from rpython.rtyper.lltypesystem import lltype
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rlib.rarithmetic import r_uint, intmask
-from rpython.rlib.rarithmetic import int_c_div, int_c_mod
+from rpython.rlib.rarithmetic import int_c_div, int_c_mod, mulmod
 from rpython.rlib import jit
 
 
@@ -39,3 +39,7 @@
     n = r_uint(n)
     x = llop.uint_rshift(lltype.Unsigned, n, m)
     return space.newint(intmask(x))
+
+ at unwrap_spec(a=int, b=int, c=int)
+def int_mulmod(space, a, b, c):
+    return space.newint(mulmod(a, b, c))
diff --git a/pypy/module/__pypy__/test/test_intop.py b/pypy/module/__pypy__/test/test_intop.py
--- a/pypy/module/__pypy__/test/test_intop.py
+++ b/pypy/module/__pypy__/test/test_intop.py
@@ -102,3 +102,7 @@
         assert intop.uint_rshift(-1, 1) == sys.maxsize
         assert intop.uint_rshift(-1, bits-2) == 3
         assert intop.uint_rshift(-1, bits-1) == 1
+
+    def test_mulmod(self):
+        from __pypy__ import intop
+        assert intop.int_mulmod(9373891, 9832739, 2**31-1) == 1025488209
diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -3,7 +3,7 @@
 from rpython.rlib import rdynload, clibffi
 from rpython.rtyper.lltypesystem import rffi
 
-VERSION = "1.11.5"
+VERSION = "1.12.0"
 
 FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI
 try:
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -258,6 +258,11 @@
 SF_PACKED             = 0x08
 SF_STD_FIELD_POS      = 0x80
 
+if sys.platform == 'win32':
+    SF_DEFAULT_PACKING = 8
+else:
+    SF_DEFAULT_PACKING = 0x40000000    # a huge power of two
+
 
 if sys.platform == 'win32':
     DEFAULT_SFLAGS_PLATFORM = SF_MSVC_BITFIELDS
@@ -309,10 +314,18 @@
         w_ctype._custom_field_pos = True
 
 @unwrap_spec(w_ctype=ctypeobj.W_CType, totalsize=int, totalalignment=int,
-             sflags=int)
+             sflags=int, pack=int)
 def complete_struct_or_union(space, w_ctype, w_fields, w_ignored=None,
-                             totalsize=-1, totalalignment=-1, sflags=0):
+                             totalsize=-1, totalalignment=-1, sflags=0,
+                             pack=0):
     sflags = complete_sflags(sflags)
+    if sflags & SF_PACKED:
+        pack = 1
+    elif pack <= 0:
+        pack = SF_DEFAULT_PACKING
+    else:
+        sflags |= SF_PACKED
+
     if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion)
             or w_ctype.size >= 0):
         raise oefmt(space.w_TypeError,
@@ -362,7 +375,7 @@
         # update the total alignment requirement, but skip it if the
         # field is an anonymous bitfield or if SF_PACKED
         falignorg = ftype.alignof()
-        falign = 1 if sflags & SF_PACKED else falignorg
+        falign = min(pack, falignorg)
         do_align = True
         if (sflags & SF_GCC_ARM_BITFIELDS) == 0 and fbitsize >= 0:
             if (sflags & SF_MSVC_BITFIELDS) == 0:
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -1,7 +1,7 @@
 # ____________________________________________________________
 
 import sys
-assert __version__ == "1.11.5", ("This test_c.py file is for testing a version"
+assert __version__ == "1.12.0", ("This test_c.py file is for testing a version"
                                  " of cffi that differs from the one that we"
                                  " get from 'import _cffi_backend'")
 if sys.version_info < (3,):
@@ -3541,30 +3541,50 @@
     BLong = new_primitive_type("long")
     BChar = new_primitive_type("char")
     BShort = new_primitive_type("short")
-    BStruct = new_struct_type("struct foo")
-    complete_struct_or_union(BStruct, [('a1', BLong, -1),
-                                       ('a2', BChar, -1),
-                                       ('a3', BShort, -1)],
-                             None, -1, -1, SF_PACKED)
-    d = BStruct.fields
-    assert len(d) == 3
-    assert d[0][0] == 'a1'
-    assert d[0][1].type is BLong
+    for extra_args in [(SF_PACKED,), (0, 1)]:
+        BStruct = new_struct_type("struct foo")
+        complete_struct_or_union(BStruct, [('a1', BLong, -1),
+                                           ('a2', BChar, -1),
+                                           ('a3', BShort, -1)],
+                                 None, -1, -1, *extra_args)
+        d = BStruct.fields
+        assert len(d) == 3
+        assert d[0][0] == 'a1'
+        assert d[0][1].type is BLong
+        assert d[0][1].offset == 0
+        assert d[0][1].bitshift == -1
+        assert d[0][1].bitsize == -1
+        assert d[1][0] == 'a2'
+        assert d[1][1].type is BChar
+        assert d[1][1].offset == sizeof(BLong)
+        assert d[1][1].bitshift == -1
+        assert d[1][1].bitsize == -1
+        assert d[2][0] == 'a3'
+        assert d[2][1].type is BShort
+        assert d[2][1].offset == sizeof(BLong) + sizeof(BChar)
+        assert d[2][1].bitshift == -1
+        assert d[2][1].bitsize == -1
+        assert sizeof(BStruct) == sizeof(BLong) + sizeof(BChar) + sizeof(BShort)
+        assert alignof(BStruct) == 1
+    #
+    BStruct2 = new_struct_type("struct foo")
+    complete_struct_or_union(BStruct2, [('b1', BChar, -1),
+                                        ('b2', BLong, -1)],
+                             None, -1, -1, 0, 2)
+    d = BStruct2.fields
+    assert len(d) == 2
+    assert d[0][0] == 'b1'
+    assert d[0][1].type is BChar
     assert d[0][1].offset == 0
     assert d[0][1].bitshift == -1
     assert d[0][1].bitsize == -1
-    assert d[1][0] == 'a2'
-    assert d[1][1].type is BChar
-    assert d[1][1].offset == sizeof(BLong)
+    assert d[1][0] == 'b2'
+    assert d[1][1].type is BLong
+    assert d[1][1].offset == 2
     assert d[1][1].bitshift == -1
     assert d[1][1].bitsize == -1
-    assert d[2][0] == 'a3'
-    assert d[2][1].type is BShort
-    assert d[2][1].offset == sizeof(BLong) + sizeof(BChar)
-    assert d[2][1].bitshift == -1
-    assert d[2][1].bitsize == -1
-    assert sizeof(BStruct) == sizeof(BLong) + sizeof(BChar) + sizeof(BShort)
-    assert alignof(BStruct) == 1
+    assert sizeof(BStruct2) == 2 + sizeof(BLong)
+    assert alignof(BStruct2) == 2
 
 def test_packed_with_bitfields():
     if sys.platform == "win32":
@@ -3915,8 +3935,8 @@
 
 def test_char_pointer_conversion():
     import warnings
-    assert __version__.startswith(("1.8", "1.9", "1.10", "1.11")), (
-        "consider turning the warning into an error")
+    assert __version__.startswith("1."), (
+        "the warning will be an error if we ever release cffi 2.x")
     BCharP = new_pointer_type(new_primitive_type("char"))
     BIntP = new_pointer_type(new_primitive_type("int"))
     BVoidP = new_pointer_type(new_void_type())
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
@@ -1,15 +1,12 @@
 import sys
 
 from pypy.interpreter.error import OperationError, oefmt
-
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib.rarithmetic import r_singlefloat, r_longfloat
 from rpython.rlib import rfloat, rawrefcount
-
 from pypy.module._rawffi.interp_rawffi import letter2tp
 from pypy.module._rawffi.array import W_ArrayInstance
-
-from pypy.module._cppyy import helper, capi, ffitypes
+from pypy.module._cppyy import helper, capi, ffitypes, lowlevelviews
 
 # Converter objects are used to translate between RPython and C++. They are
 # defined by the type name for which they provide conversion. Uses are for
@@ -82,10 +79,9 @@
 
 
 class TypeConverter(object):
-    _immutable_fields_ = ['cffi_name', 'uses_local', 'name']
+    _immutable_fields_ = ['cffi_name', 'name']
 
     cffi_name  = None
-    uses_local = False
     name       = ""
 
     def __init__(self, space, extra):
@@ -108,10 +104,10 @@
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         self._is_abstract(space)
 
-    def convert_argument_libffi(self, space, w_obj, address, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, scratch):
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
@@ -125,10 +121,10 @@
     def to_memory(self, space, w_obj, w_value, offset):
         self._is_abstract(space)
 
-    def finalize_call(self, space, w_obj, call_local):
+    def finalize_call(self, space, w_obj):
         pass
 
-    def free_argument(self, space, arg, call_local):
+    def free_argument(self, space, arg):
         pass
 
 
@@ -150,7 +146,8 @@
         # read access, so no copy needed
         address_value = self._get_raw_address(space, w_obj, offset)
         address = rffi.cast(rffi.ULONG, address_value)
-        return W_ArrayInstance(space, letter2tp(space, self.typecode), self.size, address)
+        return lowlevelviews.W_LowLevelView(
+            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)
@@ -172,7 +169,7 @@
         state = space.fromcache(ffitypes.State)
         return state.c_voidp
 
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         w_tc = space.findattr(w_obj, space.newtext('typecode'))
         if w_tc is not None and space.text_w(w_tc) != self.typecode:
             raise oefmt(space.w_TypeError,
@@ -191,7 +188,8 @@
         # read access, so no copy needed
         address_value = self._get_raw_address(space, w_obj, offset)
         address = rffi.cast(rffi.ULONGP, address_value)
-        return W_ArrayInstance(space, letter2tp(space, self.typecode), self.size, address[0])
+        return lowlevelviews.W_LowLevelView(
+            space, letter2tp(space, self.typecode), self.size, address[0])
 
     def to_memory(self, space, w_obj, w_value, offset):
         # copy only the pointer value
@@ -208,7 +206,7 @@
 class NumericTypeConverterMixin(object):
     _mixin_ = True
 
-    def convert_argument_libffi(self, space, w_obj, address, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, scratch):
         x = rffi.cast(self.c_ptrtype, address)
         x[0] = self._unwrap_object(space, w_obj)
 
@@ -228,26 +226,23 @@
 
 class ConstRefNumericTypeConverterMixin(NumericTypeConverterMixin):
     _mixin_ = True
-    _immutable_fields_ = ['uses_local']
-
-    uses_local = True
 
     def cffi_type(self, space):
         state = space.fromcache(ffitypes.State)
         return state.c_voidp
 
-    def convert_argument_libffi(self, space, w_obj, address, call_local):
-        assert rffi.sizeof(self.c_type) <= 2*rffi.sizeof(rffi.VOIDP)  # see interp_cppyy.py
+    def convert_argument_libffi(self, space, w_obj, address, scratch):
         obj = self._unwrap_object(space, w_obj)
-        typed_buf = rffi.cast(self.c_ptrtype, call_local)
+        typed_buf = rffi.cast(self.c_ptrtype, scratch)
         typed_buf[0] = obj
         x = rffi.cast(rffi.VOIDPP, address)
-        x[0] = call_local
+        x[0] = scratch
+
 
 class IntTypeConverterMixin(NumericTypeConverterMixin):
     _mixin_ = True
 
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         x = rffi.cast(self.c_ptrtype, address)
         x[0] = self._unwrap_object(space, w_obj)
         ba = rffi.cast(rffi.CCHARP, address)
@@ -256,7 +251,7 @@
 class FloatTypeConverterMixin(NumericTypeConverterMixin):
     _mixin_ = True
 
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         x = rffi.cast(self.c_ptrtype, address)
         x[0] = self._unwrap_object(space, w_obj)
         ba = rffi.cast(rffi.CCHARP, address)
@@ -273,18 +268,18 @@
         state = space.fromcache(ffitypes.State)
         return state.c_void
 
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         self._is_abstract(space)
 
 
 class BoolConverter(ffitypes.typeid(bool), TypeConverter):
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         x = rffi.cast(rffi.LONGP, address)
         x[0] = self._unwrap_object(space, w_obj)
         ba = rffi.cast(rffi.CCHARP, address)
         ba[capi.c_function_arg_typeoffset(space)] = 'b'
 
-    def convert_argument_libffi(self, space, w_obj, address, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, scratch):
         x = rffi.cast(rffi.LONGP, address)
         x[0] = self._unwrap_object(space, w_obj)
 
@@ -303,13 +298,13 @@
             address[0] = '\x00'
 
 class CharConverter(ffitypes.typeid(rffi.CHAR), TypeConverter):
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         x = rffi.cast(rffi.CCHARP, address)
         x[0] = self._unwrap_object(space, w_obj)
         ba = rffi.cast(rffi.CCHARP, address)
         ba[capi.c_function_arg_typeoffset(space)] = 'b'
 
-    def convert_argument_libffi(self, space, w_obj, address, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, scratch):
         x = rffi.cast(self.c_ptrtype, address)
         x[0] = self._unwrap_object(space, w_obj)
 
@@ -348,7 +343,7 @@
         state = space.fromcache(ffitypes.State)
         return state.c_voidp
 
-    def convert_argument_libffi(self, space, w_obj, address, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, scratch):
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
@@ -381,7 +376,7 @@
 
 
 class CStringConverter(TypeConverter):
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         x = rffi.cast(rffi.LONGP, address)
         arg = space.text_w(w_obj)
         x[0] = rffi.cast(rffi.LONG, rffi.str2charp(arg))
@@ -393,7 +388,7 @@
         charpptr = rffi.cast(rffi.CCHARPP, address)
         return space.newtext(rffi.charp2str(charpptr[0]))
 
-    def free_argument(self, space, arg, call_local):
+    def free_argument(self, space, arg):
         lltype.free(rffi.cast(rffi.CCHARPP, arg)[0], flavor='raw')
 
 class CStringConverterWithSize(CStringConverter):
@@ -423,13 +418,13 @@
         state = space.fromcache(ffitypes.State)
         return state.c_voidp
 
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = self._unwrap_object(space, w_obj)
         ba = rffi.cast(rffi.CCHARP, address)
         ba[capi.c_function_arg_typeoffset(space)] = 'o'
 
-    def convert_argument_libffi(self, space, w_obj, address, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, scratch):
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = self._unwrap_object(space, w_obj)
 
@@ -442,7 +437,7 @@
             from pypy.module._cppyy import interp_cppyy
             return interp_cppyy.get_nullptr(space)
         shape = letter2tp(space, 'P')
-        return W_ArrayInstance(space, shape, sys.maxint/shape.size, ptrval)
+        return lowlevelviews.W_LowLevelView(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))
@@ -452,37 +447,39 @@
             address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
 
 class VoidPtrPtrConverter(TypeConverter):
-    _immutable_fields_ = ['uses_local', 'typecode']
+    typecode = 'p'
 
-    uses_local = True
-    typecode = 'a'
+    def __init__(self, space, extra):
+        self.ref_buffer = lltype.nullptr(rffi.VOIDPP.TO)
 
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         x = rffi.cast(rffi.VOIDPP, address)
-        ba = rffi.cast(rffi.CCHARP, address)
         try:
             x[0] = get_rawbuffer(space, w_obj)
         except TypeError:
-            r = rffi.cast(rffi.VOIDPP, call_local)
-            r[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
-            x[0] = rffi.cast(rffi.VOIDP, call_local)
+            ptr = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+            self.ref_buffer = lltype.malloc(rffi.VOIDPP.TO, 1, flavor='raw')
+            self.ref_buffer[0] = ptr
+            x[0] = self.ref_buffer
+        ba = rffi.cast(rffi.CCHARP, address)
         ba[capi.c_function_arg_typeoffset(space)] = self.typecode
 
-    def finalize_call(self, space, w_obj, call_local):
-        r = rffi.cast(rffi.VOIDPP, call_local)
-        try:
-            set_rawobject(space, w_obj, r[0])
-        except OperationError:
-            pass             # no set on buffer/array/None
+    def finalize_call(self, space, w_obj):
+        if self.ref_buffer:
+            set_rawobject(space, w_obj, self.ref_buffer[0])
+
+    def free_argument(self, space, arg):
+        if self.ref_buffer:
+            lltype.free(self.ref_buffer, flavor='raw')
+            self.ref_buffer = lltype.nullptr(rffi.VOIDPP.TO)
 
 class VoidPtrRefConverter(VoidPtrPtrConverter):
-    _immutable_fields_ = ['uses_local', 'typecode']
-    uses_local = True
+    _immutable_fields_ = ['typecode']
     typecode   = 'V'
 
 class InstanceRefConverter(TypeConverter):
     _immutable_fields_ = ['typecode', 'clsdecl']
-    typecode    = 'V'
+    typecode = 'V'
 
     def __init__(self, space, clsdecl):
         from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl
@@ -493,7 +490,7 @@
         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_RVALUE
-            if w_obj.flags & INSTANCE_FLAGS_IS_RVALUE:
+            if w_obj.rt_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):
@@ -508,14 +505,14 @@
         state = space.fromcache(ffitypes.State)
         return state.c_voidp
 
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         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 convert_argument_libffi(self, space, w_obj, address, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, scratch):
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
 
@@ -525,21 +522,21 @@
         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
+            if obj.rt_flags & INSTANCE_FLAGS_IS_RVALUE:
+                obj.rt_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
+                    obj.rt_flags |= INSTANCE_FLAGS_IS_RVALUE
                     raise
         raise oefmt(space.w_ValueError, "object is not an rvalue")
 
 
 class InstanceConverter(InstanceRefConverter):
 
-    def convert_argument_libffi(self, space, w_obj, address, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, scratch):
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible       # TODO: by-value is a jit_libffi special case
 
@@ -551,9 +548,8 @@
     def to_memory(self, space, w_obj, w_value, offset):
         self._is_abstract(space)
 
-
 class InstancePtrConverter(InstanceRefConverter):
-    typecode    = 'o'
+    typecode = 'o'
 
     def _unwrap_object(self, space, w_obj):
         try:
@@ -569,43 +565,62 @@
         from pypy.module._cppyy import interp_cppyy
         return interp_cppyy.wrap_cppinstance(space, address, self.clsdecl, do_cast=False)
 
-    def to_memory(self, space, w_obj, w_value, offset):
-        address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset))
-        address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
+class InstancePtrPtrConverter(InstancePtrConverter):
+    typecode = 'o'
 
-class InstancePtrPtrConverter(InstancePtrConverter):
-    _immutable_fields_ = ['uses_local']
+    def __init__(self, space, extra):
+        InstancePtrConverter.__init__(self, space, extra)
+        self.ref_buffer = lltype.nullptr(rffi.VOIDPP.TO)
 
-    uses_local = True
+    def convert_argument(self, space, w_obj, address):
+        x = rffi.cast(rffi.VOIDPP, address)
+        ptr = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
+        self.ref_buffer = lltype.malloc(rffi.VOIDPP.TO, 1, flavor='raw')
+        self.ref_buffer[0] = ptr
+        x[0] = self.ref_buffer
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset(space)] = self.typecode
 
-    def convert_argument(self, space, w_obj, address, call_local):
-        r = rffi.cast(rffi.VOIDPP, call_local)
-        r[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
-        x = rffi.cast(rffi.VOIDPP, address)
-        x[0] = rffi.cast(rffi.VOIDP, call_local)
-        address = rffi.cast(capi.C_OBJECT, address)
-        ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset(space)] = 'o'
-
-    def convert_argument_libffi(self, space, w_obj, address, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, scratch):
         # TODO: finalize_call not yet called for fast call (see interp_cppyy.py)
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
-    def finalize_call(self, space, w_obj, call_local):
-        from pypy.module._cppyy.interp_cppyy import W_CPPInstance
-        assert isinstance(w_obj, W_CPPInstance)
-        r = rffi.cast(rffi.VOIDPP, call_local)
-        w_obj._rawobject = rffi.cast(capi.C_OBJECT, r[0])
-
     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.clsdecl, do_cast=False, is_ref=True)
 
+    def to_memory(self, space, w_obj, w_value, offset):
+        # the actual data member is of object* type, but we receive a pointer to that
+        # data member in order to modify its value, so by convention, the internal type
+        # used is object**
+        address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset))
+        from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+        cppinstance = space.interp_w(W_CPPInstance, w_value, can_be_None=True)
+        if cppinstance:
+            rawobject = cppinstance.get_rawobject()
+            offset = capi.c_base_offset(space, cppinstance.clsdecl, self.clsdecl, rawobject, 1)
+            obj_address = capi.direct_ptradd(rawobject, offset)
+            address[0] = rffi.cast(rffi.VOIDP, obj_address);
+            # register the value for potential recycling
+            from pypy.module._cppyy.interp_cppyy import memory_regulator
+            memory_regulator.register(cppinstance)
+        else:
+            raise oefmt(space.w_TypeError,
+                "cannot pass %T instance as %s", w_value, self.clsdecl.name)
+
+    def finalize_call(self, space, w_obj):
+        if self.ref_buffer:
+            set_rawobject(space, w_obj, self.ref_buffer[0])
+
+    def free_argument(self, space, arg):
+        if self.ref_buffer:
+            lltype.free(self.ref_buffer, flavor='raw')
+            self.ref_buffer = lltype.nullptr(rffi.VOIDPP.TO)
+
 class StdStringConverter(InstanceConverter):
-
     def __init__(self, space, extra):
         from pypy.module._cppyy import interp_cppyy
         cppclass = interp_cppyy.scope_byname(space, capi.std_string_name)
@@ -628,9 +643,37 @@
         except Exception:
             InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
 
-    def free_argument(self, space, arg, call_local):
+    def free_argument(self, space, arg):
         capi.c_destruct(space, self.clsdecl, rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
 
+class StdStringMoveConverter(StdStringConverter):
+    def _unwrap_object(self, space, w_obj):
+        # moving is same as by-ref, but have to check that move is allowed
+        moveit_reason = 3
+        from pypy.module._cppyy.interp_cppyy import W_CPPInstance, INSTANCE_FLAGS_IS_RVALUE
+        try:
+            obj = space.interp_w(W_CPPInstance, w_obj)
+            if obj and obj.rt_flags & INSTANCE_FLAGS_IS_RVALUE:
+                obj.rt_flags &= ~INSTANCE_FLAGS_IS_RVALUE
+                moveit_reason = 1
+            else:
+                moveit_reason = 0
+        except:
+            pass
+
+        if moveit_reason:
+            try:
+                return StdStringConverter._unwrap_object(self, space, w_obj)
+            except Exception:
+                 if moveit_reason == 1:
+                    # TODO: if the method fails on some other converter, then the next
+                    # overload can not be an rvalue anymore
+                    obj = space.interp_w(W_CPPInstance, w_obj)
+                    obj.rt_flags |= INSTANCE_FLAGS_IS_RVALUE
+                    raise
+
+        raise oefmt(space.w_ValueError, "object is not an rvalue")
+
 class StdStringRefConverter(InstancePtrConverter):
     _immutable_fields_ = ['cppclass', 'typecode']
     typecode    = 'V'
@@ -646,7 +689,7 @@
         state = space.fromcache(ffitypes.State)
         return state.c_voidp
 
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         if hasattr(space, "fake"):
             raise NotImplementedError
         space.getbuiltinmodule("cpyext")
@@ -657,7 +700,7 @@
         ba = rffi.cast(rffi.CCHARP, address)
         ba[capi.c_function_arg_typeoffset(space)] = 'a'
 
-    def convert_argument_libffi(self, space, w_obj, address, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, scratch):
         # TODO: free_argument not yet called for fast call (see interp_cppyy.py)
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
@@ -671,7 +714,7 @@
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = rffi.cast(rffi.VOIDP, ref)"""
 
-    def free_argument(self, space, arg, call_local):
+    def free_argument(self, space, arg):
         if hasattr(space, "fake"):
             raise NotImplementedError
         space.getbuiltinmodule("cpyext")
@@ -685,7 +728,7 @@
     def __init__(self, space, signature):
         self.signature = signature
 
-    def convert_argument(self, space, w_obj, address, call_local):
+    def convert_argument(self, space, w_obj, address):
         # TODO: atm, does not actually get an overload, but a staticmethod
         from pypy.module._cppyy.interp_cppyy import W_CPPOverload
         cppol = space.interp_w(W_CPPOverload, w_obj)
@@ -740,7 +783,7 @@
         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):
+    def convert_argument(self, space, w_obj, address):
         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)
@@ -883,6 +926,7 @@
 _converters["std::basic_string<char>"]           = StdStringConverter
 _converters["const std::basic_string<char>&"]    = StdStringConverter     # TODO: shouldn't copy
 _converters["std::basic_string<char>&"]          = StdStringRefConverter
+_converters["std::basic_string<char>&&"]         = StdStringMoveConverter
 
 _converters["PyObject*"]                         = PyObjectConverter
 
@@ -1000,6 +1044,7 @@
         ("std::basic_string<char>",         "string"),
         ("const std::basic_string<char>&",  "const string&"),
         ("std::basic_string<char>&",        "string&"),
+        ("std::basic_string<char>&&",       "string&&"),
 
         ("PyObject*",                       "_object*"),
     )
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
@@ -1,14 +1,10 @@
 import sys
 
 from pypy.interpreter.error import oefmt
-
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib import jit_libffi
-
 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
+from pypy.module._cppyy import helper, capi, ffitypes, lowlevelviews
 
 # Executor objects are used to dispatch C++ methods. They are defined by their
 # return type only: arguments are converted by Converter objects, and Executors
@@ -60,7 +56,7 @@
             from pypy.module._cppyy import interp_cppyy
             return interp_cppyy.get_nullptr(space)
         shape = letter2tp(space, self.typecode)
-        return W_ArrayInstance(space, shape, sys.maxint/shape.size, ptrval)
+        return lowlevelviews.W_LowLevelView(space, shape, sys.maxint/shape.size, ptrval)
 
 
 class VoidExecutor(Executor):
@@ -98,10 +94,10 @@
     def __init__(self, space, extra):
         Executor.__init__(self, space, extra)
         self.do_assign = False
-        self.item = rffi.cast(self.c_type, 0)
+        self.w_item = space.w_None
 
     def set_item(self, space, w_item):
-        self.item = self._unwrap_object(space, w_item)
+        self.w_item = w_item
         self.do_assign = True
 
     #def _wrap_object(self, space, obj):
@@ -109,7 +105,7 @@
 
     def _wrap_reference(self, space, rffiptr):
         if self.do_assign:
-            rffiptr[0] = self.item
+            rffiptr[0] = rffi.cast(self.c_type, self._unwrap_object(space, self.w_item))
         self.do_assign = False
         return self._wrap_object(space, rffiptr[0])    # all paths, for rtyper
 
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
@@ -1,6 +1,9 @@
 import pypy.module._cppyy.capi as capi
 
 from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.function import Method
+from pypy.interpreter.argument import Arguments
+from pypy.interpreter.typedef import interp_attrproperty_w, descr_generic_ne, make_weakref_descr
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
 from pypy.interpreter.baseobjspace import W_Root
@@ -38,6 +41,7 @@
              'void**'        : 100,
              'float'         :  30,
              'double'        :  10,
+             'bool'          :   1,
              'const string&' :   1, } # solves a specific string ctor overload
 
 from rpython.rlib.listsort import make_timsort_class
@@ -164,13 +168,16 @@
 #
 #  W_CPPOverload:                 instance methods (base class)
 #  W_CPPConstructorOverload:      constructors
+#  W_CPPAbstractCtorOverload:     to provent instantiation of abstract classes
 #  W_CPPStaticOverload:           free and static functions
 #  W_CPPTemplateOverload:         templated methods
-#  W_CPPTemplateStaticOveload:    templated free and static functions
+#  W_CPPTemplateStaticOverload:   templated free and static functions
 #
 #  CPPMethod:         a single function or method (base class)
 #  CPPSetItem:        specialization for Python's __setitem__
 #
+#  MethodWithProps:   python instancemethod that forwards properties
+#
 # All methods/functions derive from CPPMethod and are collected as overload
 # candidates in user-facing overload classes. Templated methods are a two-step
 # process, where first the template is instantiated (or selected if already
@@ -183,13 +190,13 @@
     the memory_regulator."""
 
     _attrs_ = ['space', 'scope', 'cppmethod', 'arg_defs', 'args_required',
-               'converters', 'executor', '_funcaddr', 'cif_descr', 'uses_local']
+               'converters', 'executor', '_funcaddr', 'cif_descr']
     _immutable_fields_ = ['scope', 'cppmethod', 'arg_defs', 'args_required',
-                          'converters', 'executor', 'uses_local']
+               'converters', 'executor', '_funcaddr', 'cif_descr']
 
-    def __init__(self, space, declaring_scope, cppmethod, arg_defs, args_required):
+    def __init__(self, space, decl_scope, cppmethod, arg_defs, args_required):
         self.space = space
-        self.scope = declaring_scope
+        self.scope = decl_scope
         self.cppmethod = cppmethod
         self.arg_defs = arg_defs
         self.args_required = args_required
@@ -200,14 +207,6 @@
         self.executor = None
         self.cif_descr = lltype.nullptr(jit_libffi.CIF_DESCRIPTION)
         self._funcaddr = lltype.nullptr(capi.C_FUNC_PTR.TO)
-        self.uses_local = False
-
-    def _address_from_local_buffer(self, call_local, idx):
-        if not call_local:
-            return call_local
-        stride = 2*rffi.sizeof(rffi.VOIDP)
-        loc_idx = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, call_local), idx*stride)
-        return rffi.cast(rffi.VOIDP, loc_idx)
 
     @jit.unroll_safe
     def call(self, cppthis, args_w, useffi):
@@ -233,61 +232,56 @@
             except Exception:
                 pass
 
-        # some calls, e.g. for ptr-ptr or reference need a local array to store data for
-        # the duration of the call
-        if self.uses_local:
-            call_local = lltype.malloc(rffi.VOIDP.TO, 2*len(args_w), flavor='raw')
-        else:
-            call_local = lltype.nullptr(rffi.VOIDP.TO)
+        # attempt to call directly through ffi chain
+        if useffi and self._funcaddr:
+            try:
+                return self.do_fast_call(cppthis, args_w)
+            except FastCallNotPossible:
+                pass      # can happen if converters or executor does not implement ffi
 
+        # ffi chain must have failed; using stub functions instead
+        args, stat = self.prepare_arguments(args_w)
         try:
-            # attempt to call directly through ffi chain
-            if useffi and self._funcaddr:
-                try:
-                    return self.do_fast_call(cppthis, args_w, call_local)
-                except FastCallNotPossible:
-                    pass      # can happen if converters or executor does not implement ffi
-
-            # ffi chain must have failed; using stub functions instead
-            args, stat = self.prepare_arguments(args_w, call_local)
-            try:
-                result = self.executor.execute(
-                    self.space, self.cppmethod, cppthis, len(args_w), args)
-                if stat[0] != rffi.cast(rffi.ULONG, 0):
-                    what = rffi.cast(rffi.CCHARP, stat[1])
-                    pywhat = rffi.charp2str(what)
-                    capi.c_free(self.space, rffi.cast(rffi.VOIDP, what))
-                    raise OperationError(self.space.w_Exception, self.space.newtext(pywhat))
-                return result
-            finally:
-                self.finalize_call(args, args_w, call_local)
+            result = self.executor.execute(
+                self.space, self.cppmethod, cppthis, len(args_w), args)
+            if stat[0] != rffi.cast(rffi.ULONG, 0):
+                what = rffi.cast(rffi.CCHARP, stat[1])
+                pywhat = rffi.charp2str(what)
+                capi.c_free(self.space, rffi.cast(rffi.VOIDP, what))
+                raise OperationError(self.space.w_Exception, self.space.newtext(pywhat))
+            return result
         finally:
-            if call_local:
-                lltype.free(call_local, flavor='raw')
+            self.finalize_call(args, args_w)
 
     @jit.unroll_safe
-    def do_fast_call(self, cppthis, args_w, call_local):
+    def do_fast_call(self, cppthis, args_w):
         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')
+        # add extra space for const-ref support (see converter.py)
+        buffer = lltype.malloc(rffi.CCHARP.TO,
+            cif_descr.exchange_size+len(self.arg_defs)*rffi.sizeof(rffi.DOUBLE), flavor='raw')
+        thisoff = 0
         try:
-            # this pointer
-            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)
+            if cppthis:
+                # this pointer
+                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)
+                thisoff = 1
 
-            # other arguments and defaults
-            i = len(self.arg_defs) + 1
+            # actual provided arguments
+            i = -1      # needed if all arguments are defaults
             for i in range(len(args_w)):
                 conv = self.converters[i]
-                w_arg = args_w[i]
-                data = rffi.ptradd(buffer, cif_descr.exchange_args[i+1])
-                conv.convert_argument_libffi(self.space, w_arg, data, call_local)
+                data = rffi.ptradd(buffer, cif_descr.exchange_args[i+thisoff])
+                scratch = rffi.ptradd(buffer, cif_descr.exchange_size+i*rffi.sizeof(rffi.DOUBLE))
+                conv.convert_argument_libffi(self.space, args_w[i], data, scratch)
+            # drop in defaults for the rest
             for j in range(i+1, len(self.arg_defs)):
                 conv = self.converters[j]
-                data = rffi.ptradd(buffer, cif_descr.exchange_args[j+1])
+                data = rffi.ptradd(buffer, cif_descr.exchange_args[j+thisoff])
                 conv.default_argument_libffi(self.space, data)
 
             assert self._funcaddr
@@ -346,22 +340,17 @@
         self.executor = executor.get_executor(
             self.space, capi.c_method_result_type(self.space, self.cppmethod))
 
-        for conv in self.converters:
-            if conv.uses_local:
-                self.uses_local = True
-                break
-
         # 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(self.space, self.cppmethod)
-        if funcaddr and cppthis:      # TODO: methods only for now
+        if funcaddr:
             state = self.space.fromcache(ffitypes.State)
 
-            # argument type specification (incl. cppthis)
+            # argument type specification (incl. cppthis if applicable)
             fargs = []
             try:
-                fargs.append(state.c_voidp)
+                if cppthis: fargs.append(state.c_voidp)
                 for i, conv in enumerate(self.converters):
                     fargs.append(conv.cffi_type(self.space))
                 fresult = self.executor.cffi_type(self.space)
@@ -386,7 +375,7 @@
             self._funcaddr = funcaddr
 
     @jit.unroll_safe
-    def prepare_arguments(self, args_w, call_local):
+    def prepare_arguments(self, args_w):
         args = capi.c_allocate_function_args(self.space, len(args_w))
         stride = capi.c_function_arg_sizeof(self.space)
         for i in range(len(args_w)):
@@ -394,15 +383,13 @@
             w_arg = args_w[i]
             try:
                 arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
-                loc_i = self._address_from_local_buffer(call_local, i)
-                conv.convert_argument(self.space, w_arg, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
+                conv.convert_argument(self.space, w_arg, rffi.cast(capi.C_OBJECT, arg_i))
             except:
                 # fun :-(
                 for j in range(i):
                     conv = self.converters[j]
                     arg_j = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), j*stride)
-                    loc_j = self._address_from_local_buffer(call_local, j)
-                    conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_j), loc_j)
+                    conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_j))
                 capi.c_deallocate_function_args(self.space, args)
                 raise
         stat = rffi.cast(rffi.ULONGP,
@@ -411,14 +398,13 @@
         return args, stat
 
     @jit.unroll_safe
-    def finalize_call(self, args, args_w, call_local):
+    def finalize_call(self, args, args_w):
         stride = capi.c_function_arg_sizeof(self.space)
         for i in range(len(args_w)):
             conv = self.converters[i]
             arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
-            loc_i = self._address_from_local_buffer(call_local, i)
-            conv.finalize_call(self.space, args_w[i], loc_i)
-            conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
+            conv.finalize_call(self.space, args_w[i])
+            conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_i))
         capi.c_deallocate_function_args(self.space, args)
 
     def signature(self, show_formalargs=True):
@@ -429,8 +415,10 @@
 
     def priority(self):
         total_arg_priority = 0
-        for p in [priority.get(arg_type, 0) for arg_type, arg_dflt in self.arg_defs]:
-            total_arg_priority += p
+        for arg_type, arg_dflt in self.arg_defs:
+            total_arg_priority += priority.get(arg_type, 0)
+            if '&&' in arg_type:
+                total_arg_priority += 100
         return total_arg_priority
 
     @rgc.must_be_light_finalizer
@@ -450,7 +438,7 @@
 
 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
+    operator[](T). The former function takes an extra argument to assign to
     the return type of the latter."""
 
     _attrs_ = []
@@ -466,42 +454,81 @@
         CPPMethod.call(self, cppthis, args_w, useffi)
 
 
+# CPPOverloads have settable flags that control memory and ffi behavior. These flags
+# need forwarding, which the normal instancemethod does not provide, hence this
+# derived class.
+class MethodWithProps(Method):
+    # allow user to determine ffi use rules per overload
+    def fget_useffi(self, space):
+        f = space.interp_w(W_CPPOverload, self.w_function)
+        return f.fget_useffi(space)
+
+    @unwrap_spec(value=bool)
+    def fset_useffi(self, space, value):
+        f = space.interp_w(W_CPPOverload, self.w_function)
+        f.fset_useffi(space, value)
+
+MethodWithProps.typedef = TypeDef(
+    "cpp_instancemethod",
+    __doc__ = """cpp_instancemethod(function, instance, class)
+
+Create an instance method object.""",
+    __new__ = interp2app(MethodWithProps.descr_method__new__.im_func),
+    __call__ = interp2app(MethodWithProps.descr_method_call),
+    __get__ = interp2app(MethodWithProps.descr_method_get),
+    __func__ = interp_attrproperty_w('w_function', cls=MethodWithProps),
+    __self__ = interp_attrproperty_w('w_instance', cls=MethodWithProps),
+    __getattribute__ = interp2app(MethodWithProps.descr_method_getattribute),
+    __eq__ = interp2app(MethodWithProps.descr_method_eq),
+    __ne__ = descr_generic_ne,
+    __hash__ = interp2app(MethodWithProps.descr_method_hash),
+    __repr__ = interp2app(MethodWithProps.descr_method_repr),
+    __reduce__ = interp2app(MethodWithProps.descr_method__reduce__),
+    __weakref__ = make_weakref_descr(MethodWithProps),
+    __useffi__ = GetSetProperty(MethodWithProps.fget_useffi, MethodWithProps.fset_useffi),
+    )
+MethodWithProps.typedef.acceptable_as_base_class = False
+
+
 class W_CPPOverload(W_Root):
     """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', 'w_this']
+    _attrs_ = ['space', 'scope', 'functions', 'flags']
     _immutable_fields_ = ['scope', 'functions[*]']
 
-    def __init__(self, space, declaring_scope, functions, flags = OVERLOAD_FLAGS_USE_FFI):
+    def __init__(self, space, decl_scope, funcs, flags = OVERLOAD_FLAGS_USE_FFI):
         self.space  = space
-        self.scope  = declaring_scope
+        self.scope  = decl_scope
         from rpython.rlib import debug
-        self.functions = debug.make_sure_not_resized(functions)
+        self.functions = debug.make_sure_not_resized(funcs)
         self.flags  = flags
-        self.w_this = self.space.w_None
+
+    def descr_get(self, w_obj, w_cls=None):
+        """functionobject.__get__(obj[, type]) -> method"""
+        # TODO: check validity of w_cls if given
+        # TODO: this does not work for Python 3, which does not have
+        #  unbound methods (probably no common code possible, see also
+        #  pypy/interpreter/function.py)
+        space = self.space
+        asking_for_bound = (space.is_none(w_cls) or
+                            not space.is_w(w_obj, space.w_None) or
+                            space.is_w(w_cls, space.type(space.w_None)))
+        if asking_for_bound:
+            return MethodWithProps(space, self, w_obj)
+        else:
+            return self   # unbound methods don't exist in Python 3
 
     @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(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:
-            w_this = self.w_this
+    def call_args(self, args_w):
+        jit.promote(self)
+        w_this = args_w[0]
         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)
+        return self.call_impl(cppinstance.get_cppthis(self.scope), args_w[1:])
 
     @jit.unroll_safe
     def call_impl(self, cppthis, args_w):
@@ -562,6 +589,16 @@
             sig += '\n'+self.functions[i].prototype()
         return self.space.newtext(sig)
 
+    @unwrap_spec(signature='text')
+    def mp_overload(self, signature):
+        sig = '(%s)' % signature
+        for f in self.functions:
+            if f.signature(False) == sig:
+                if isinstance(self, W_CPPStaticOverload):
+                    return W_CPPStaticOverload(self.space, self.scope, [f])
+                return W_CPPOverload(self.space, self.scope, [f])
+        raise oefmt(self.space.w_LookupError, "signature '%s' not found", signature)
+
     # allow user to determine ffi use rules per overload
     def fget_useffi(self, space):
         return space.newbool(bool(self.flags & OVERLOAD_FLAGS_USE_FFI))
@@ -576,15 +613,20 @@
     def fget_doc(self, space):
         return self.prototype()
 
+    def getname(self, space): 
+        # for the benefit of Method/instancemethod
+        return capi.c_method_name(space, self.functions[0].cppmethod).decode('latin-1')
+
     def __repr__(self):
         return "W_CPPOverload(%s)" % [f.prototype() for f in self.functions]
 
 W_CPPOverload.typedef = TypeDef(
     'CPPOverload',
-    __get__    = interp2app(W_CPPOverload.descr_get),
-    __call__   = interp2app(W_CPPOverload.call),
-    __useffi__ = GetSetProperty(W_CPPOverload.fget_useffi, W_CPPOverload.fset_useffi),
-    __doc__    = GetSetProperty(W_CPPOverload.fget_doc)
+    __get__      = interp2app(W_CPPOverload.descr_get),
+    __call__     = interp2app(W_CPPOverload.call_args),
+    __useffi__   = GetSetProperty(W_CPPOverload.fget_useffi, W_CPPOverload.fset_useffi),
+    __overload__ = interp2app(W_CPPOverload.mp_overload),
+    __doc__      = GetSetProperty(W_CPPOverload.fget_doc)
 )
 
 
@@ -593,26 +635,19 @@
 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):
+    def descr_get(self, w_obj, w_cls=None):
+        if isinstance(w_obj, 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)
+            cppinstance = self.space.interp_w(W_CPPInstance, w_obj)
             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 MethodWithProps(self.space, self, w_obj)    # 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
+    def call_args(self, args_w):
+        jit.promote(self)
         return self.call_impl(capi.C_NULL_OBJECT, args_w)
 
     def __repr__(self):
@@ -620,37 +655,26 @@
 
 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)
+    __get__      = interp2app(W_CPPStaticOverload.descr_get),
+    __call__     = interp2app(W_CPPStaticOverload.call_args),
+    __useffi__   = GetSetProperty(W_CPPStaticOverload.fget_useffi, W_CPPStaticOverload.fset_useffi),
+    __overload__ = interp2app(W_CPPStaticOverload.mp_overload),
+    __doc__      = GetSetProperty(W_CPPStaticOverload.fget_doc)
 )
 
 
 class W_CPPConstructorOverload(W_CPPOverload):
     _attrs_ = []
 
-    @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
+    def __init__(self, space, decl_scope, funcs, flags = OVERLOAD_FLAGS_USE_FFI):
+        W_CPPOverload.__init__(self, space, decl_scope, funcs, flags)
+        self.flags &= ~OVERLOAD_FLAGS_USE_FFI
 
     @unwrap_spec(args_w='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)
-        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)
+    def call_args(self, args_w):
+        jit.promote(self)
+        cppinstance = self.space.interp_w(W_CPPInstance, args_w[0])
+        w_result = self.call_impl(rffi.cast(capi.C_OBJECT, self.scope.handle), args_w[1:])
         newthis = rffi.cast(capi.C_OBJECT, self.space.uint_w(w_result))
         if cppinstance is not None:
             cppinstance._rawobject = newthis
@@ -661,9 +685,27 @@
 
 W_CPPConstructorOverload.typedef = TypeDef(
     'CPPConstructorOverload',
-    __get__    = interp2app(W_CPPConstructorOverload.descr_get),
-    __call__   = interp2app(W_CPPConstructorOverload.call),
-    __doc__    = GetSetProperty(W_CPPConstructorOverload.fget_doc)
+    __get__      = interp2app(W_CPPConstructorOverload.descr_get),
+    __call__     = interp2app(W_CPPConstructorOverload.call_args),
+    __overload__ = interp2app(W_CPPConstructorOverload.mp_overload),
+    __doc__      = GetSetProperty(W_CPPConstructorOverload.fget_doc)
+)
+
+class W_CPPAbstractCtorOverload(W_CPPOverload):
+    _attrs_ = []
+
+    @unwrap_spec(args_w='args_w')
+    def call_args(self, args_w):
+        raise oefmt(self.space.w_TypeError,
+            "cannot instantiate abstract class '%s'", self.scope.name)
+
+    def __repr__(self):
+        return "W_CPPAbstractCtorOverload"
+
+W_CPPAbstractCtorOverload.typedef = TypeDef(
+    'CPPAbstractCtorOverload',
+    __get__    = interp2app(W_CPPAbstractCtorOverload.descr_get),
+    __call__   = interp2app(W_CPPAbstractCtorOverload.call_args),
 )
 
 
@@ -686,7 +728,7 @@
                     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:
+                        if cppinstance.rt_flags & INSTANCE_FLAGS_IS_RVALUE:
                             sugar = "&&"
                         elif cppinstance.flags & INSTANCE_FLAGS_IS_REF:
                             sugar = "*"
@@ -725,7 +767,9 @@
         # 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)
+                if not self.space.is_w(self.w_this, self.space.w_None):
+                    return self.space.call_obj_args(cppol, self.w_this, Arguments(self.space, args_w))
+                return self.space.call_args(cppol, Arguments(self.space, args_w))
             except Exception:
                 pass    # completely ignore for now; have to see whether errors become confusing
 
@@ -748,7 +792,9 @@
             except KeyError:
                 self.master.overloads[fullname] = method
 
-        return method.descr_get(self.w_this, []).call(args_w)
+        if not self.space.is_w(self.w_this, self.space.w_None):
+            return self.space.call_obj_args(method, self.w_this, Arguments(self.space, args_w))
+        return self.space.call_args(method, Arguments(self.space, args_w))
 
     def getitem_impl(self, name, args_w):
         space = self.space
@@ -771,25 +817,25 @@
             if c_fullname != fullname:
                 self.master.overloads[c_fullname] = method
 
-        return method.descr_get(self.w_this, [])
+        return method.descr_get(self.w_this, None)
 
 
 class W_CPPTemplateOverload(W_CPPOverload, TemplateOverloadMixin):
     """App-level dispatcher to allow both lookup/instantiation of templated methods and
     dispatch among overloads between templated and non-templated method."""
 
-    _attrs_ = ['name', 'overloads', 'master']
+    _attrs_ = ['name', 'overloads', 'master', 'w_this']
     _immutable_fields_ = ['name']
 
-    def __init__(self, space, name, declaring_scope, functions, flags = OVERLOAD_FLAGS_USE_FFI):
-         W_CPPOverload.__init__(self, space, declaring_scope, functions, flags)
+    def __init__(self, space, name, decl_scope, functions, flags = OVERLOAD_FLAGS_USE_FFI):
+         W_CPPOverload.__init__(self, space, decl_scope, functions, flags)
          self.name = name
          self.overloads = {}
          self.master = self
+         self.w_this = space.w_None
 
-    @unwrap_spec(args_w='args_w')
-    def descr_get(self, w_cppinstance, args_w):
-        # like W_CPPOverload, but returns W_CPPTemplateOverload
+    def descr_get(self, w_cppinstance, w_cls=None):
+        # TODO: don't return copy, but bind in an external object (like W_CPPOverload)
         if self.space.is_w(w_cppinstance, self.space.w_None):
             return self  # unbound, so no new instance needed
         cppol = W_CPPTemplateOverload(self.space, self.name, self.scope, self.functions, self.flags)
@@ -798,13 +844,13 @@
         return cppol     # bound
 
     @unwrap_spec(args_w='args_w')
-    def call(self, args_w):
+    def call_args(self, args_w):
         # direct call: either pick non-templated overload or attempt to deduce
         # the template instantiation from the argument types
 
         # try existing overloads or compile-time instantiations
         try:
-            return W_CPPOverload.call(self, args_w)
+            return W_CPPOverload.call_args(self, args_w)
         except Exception:
             pass
 
@@ -814,34 +860,37 @@
     def getitem(self, args_w):
         return self.getitem_impl(self.name, args_w)
 
+    def getname(self, space):
+        return self.name.decode('latin-1')
+
     def __repr__(self):
         return "W_CPPTemplateOverload(%s)" % [f.prototype() for f in self.functions]
 
 W_CPPTemplateOverload.typedef = TypeDef(
     'CPPTemplateOverload',
-    __get__     = interp2app(W_CPPTemplateOverload.descr_get),
-    __getitem__ = interp2app(W_CPPTemplateOverload.getitem),
-    __call__    = interp2app(W_CPPTemplateOverload.call),
-    __useffi__  = GetSetProperty(W_CPPTemplateOverload.fget_useffi, W_CPPTemplateOverload.fset_useffi),
-    __doc__     = GetSetProperty(W_CPPTemplateOverload.fget_doc)
+    __get__      = interp2app(W_CPPTemplateOverload.descr_get),
+    __getitem__  = interp2app(W_CPPTemplateOverload.getitem),
+    __call__     = interp2app(W_CPPTemplateOverload.call_args),
+    __useffi__   = GetSetProperty(W_CPPTemplateOverload.fget_useffi, W_CPPTemplateOverload.fset_useffi),
+    __doc__      = GetSetProperty(W_CPPTemplateOverload.fget_doc)
 )
 
 class W_CPPTemplateStaticOverload(W_CPPStaticOverload, TemplateOverloadMixin):
     """App-level dispatcher to allow both lookup/instantiation of templated methods and
     dispatch among overloads between templated and non-templated method."""
 
-    _attrs_ = ['name', 'overloads', 'master']
+    _attrs_ = ['name', 'overloads', 'master', 'w_this']
     _immutable_fields_ = ['name']
 
-    def __init__(self, space, name, declaring_scope, functions, flags = OVERLOAD_FLAGS_USE_FFI):
-         W_CPPStaticOverload.__init__(self, space, declaring_scope, functions, flags)
+    def __init__(self, space, name, decl_scope, funcs, flags = OVERLOAD_FLAGS_USE_FFI):
+         W_CPPStaticOverload.__init__(self, space, decl_scope, funcs, flags)
          self.name = name
          self.overloads = {}
          self.master = self
+         self.w_this = space.w_None
 
-    @unwrap_spec(args_w='args_w')
-    def descr_get(self, w_cppinstance, args_w):
-        # like W_CPPStaticOverload, but returns W_CPPTemplateStaticOverload
+    def descr_get(self, w_cppinstance, w_cls=None):
+        # TODO: don't return copy, but bind in an external object (like W_CPPOverload)
         if isinstance(w_cppinstance, W_CPPInstance):
             cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance)
             if cppinstance.clsdecl.handle != self.scope.handle:
@@ -852,13 +901,13 @@
         return self      # unbound
 
     @unwrap_spec(args_w='args_w')
-    def call(self, args_w):
+    def call_args(self, args_w):
         # direct call: either pick non-templated overload or attempt to deduce
         # the template instantiation from the argument types
 
         # try existing overloads or compile-time instantiations
         try:
-            return W_CPPStaticOverload.call(self, args_w)
+            return W_CPPStaticOverload.call_args(self, args_w)
         except Exception:
             pass
 
@@ -869,16 +918,19 @@
     def getitem(self, args_w):
         return self.getitem_impl(self.name, args_w)
 
+    def getname(self, space):
+        return self.name.decode('latin-1')
+
     def __repr__(self):
         return "W_CPPTemplateStaticOverload(%s)" % [f.prototype() for f in self.functions]
 
 W_CPPTemplateStaticOverload.typedef = TypeDef(
     'CPPTemplateStaticOverload',
-    __get__     = interp2app(W_CPPTemplateStaticOverload.descr_get),
-    __getitem__ = interp2app(W_CPPTemplateStaticOverload.getitem),
-    __call__    = interp2app(W_CPPTemplateStaticOverload.call),
-    __useffi__  = GetSetProperty(W_CPPTemplateStaticOverload.fget_useffi, W_CPPTemplateStaticOverload.fset_useffi),
-    __doc__     = GetSetProperty(W_CPPTemplateStaticOverload.fget_doc)
+    __get__      = interp2app(W_CPPTemplateStaticOverload.descr_get),
+    __getitem__  = interp2app(W_CPPTemplateStaticOverload.getitem),
+    __call__     = interp2app(W_CPPTemplateStaticOverload.call_args),
+    __useffi__   = GetSetProperty(W_CPPTemplateStaticOverload.fget_useffi, W_CPPTemplateStaticOverload.fset_useffi),
+    __doc__      = GetSetProperty(W_CPPTemplateStaticOverload.fget_doc)
 )
 
 
@@ -898,14 +950,15 @@
     _attrs_ = ['space', 'scope', 'converter', 'offset']
     _immutable_fields = ['scope', 'converter', 'offset']
 
-    def __init__(self, space, declaring_scope, type_name, offset):
+    def __init__(self, space, decl_scope, type_name, offset):
         self.space = space
-        self.scope = declaring_scope
+        self.scope = decl_scope
         self.converter = converter.get_converter(self.space, type_name, '')
         self.offset = offset
 
     def _get_offset(self, cppinstance):
         if cppinstance:
+            assert isinstance(cppinstance.clsdecl, W_CPPClassDecl)
             assert lltype.typeOf(cppinstance.clsdecl.handle) == lltype.typeOf(self.scope.handle)
             offset = self.offset + cppinstance.clsdecl.get_base_offset(cppinstance, self.scope)
         else:
@@ -1051,6 +1104,8 @@
         sig = '(%s)' % signature
         for f in overload.functions:
             if f.signature(False) == sig:
+                if isinstance(overload, W_CPPStaticOverload):
+                    return W_CPPStaticOverload(self.space, self, [f])
                 return W_CPPOverload(self.space, self, [f])
         raise oefmt(self.space.w_LookupError, "no overload matches signature")
 
@@ -1146,9 +1201,13 @@
 
 
 class W_CPPClassDecl(W_CPPScopeDecl):
-    _attrs_ = ['space', 'handle', 'name', 'overloads', 'datamembers']
+    _attrs_ = ['space', 'handle', 'name', 'overloads', 'datamembers', 'cppobjects']
     _immutable_fields_ = ['handle', 'name', 'overloads[*]', 'datamembers[*]']
 
+    def __init__(self, space, opaque_handle, final_scoped_name):
+        W_CPPScopeDecl.__init__(self, space, opaque_handle, final_scoped_name)
+        self.cppobjects = rweakref.RWeakValueDictionary(int, W_CPPInstance)
+
     def _build_overloads(self):
         assert len(self.overloads) == 0
         methods_tmp = {}; ftype_tmp = {}
@@ -1187,7 +1246,10 @@
             ftype = ftype_tmp[pyname]
             CPPMethodSort(methods).sort()
             if ftype & FUNCTION_IS_CONSTRUCTOR:
-                overload = W_CPPConstructorOverload(self.space, self, methods[:])
+                if capi.c_is_abstract(self.space, self.handle):
+                    overload = W_CPPAbstractCtorOverload(self.space, self, methods[:])
+                else:
+                    overload = W_CPPConstructorOverload(self.space, self, methods[:])
             elif ftype & FUNCTION_IS_STATIC:
                 if ftype & FUNCTION_IS_TEMPLATE:
                     cppname = capi.c_method_name(self.space, methods[0].cppmethod)
@@ -1253,10 +1315,12 @@
         raise self.missing_attribute_error(name)
 
     def get_base_offset(self, cppinstance, calling_scope):
+        assert isinstance(cppinstance.clsdecl, W_CPPClassDecl)
         assert self == cppinstance.clsdecl
         return 0
 
     def get_cppthis(self, cppinstance, calling_scope):
+        assert isinstance(cppinstance.clsdecl, W_CPPClassDecl)
         assert self == cppinstance.clsdecl
         return cppinstance.get_rawobject()
 
@@ -1292,12 +1356,14 @@
 
 class W_CPPComplexClassDecl(W_CPPClassDecl):
     def get_base_offset(self, cppinstance, calling_scope):
+        assert isinstance(cppinstance.clsdecl, W_CPPComplexClassDecl)
         assert self == cppinstance.clsdecl
         offset = capi.c_base_offset(self.space,
-                                    self, calling_scope, cppinstance.get_rawobject(), 1)
+            self, calling_scope, cppinstance.get_rawobject(), 1)
         return offset
 
     def get_cppthis(self, cppinstance, calling_scope):
+        assert isinstance(cppinstance.clsdecl, W_CPPComplexClassDecl)
         assert self == cppinstance.clsdecl
         offset = self.get_base_offset(cppinstance, calling_scope)
         return capi.direct_ptradd(cppinstance.get_rawobject(), offset)
@@ -1317,9 +1383,9 @@
 
 
 class W_CPPInstance(W_Root):
-    _attrs_ = ['space', 'clsdecl', '_rawobject', 'smartdecl', 'deref', 'flags',
+    _attrs_ = ['space', 'clsdecl', '_rawobject', 'smartdecl', 'deref', 'flags', 'rt_flags',
                'finalizer_registered']
-    _immutable_fields_ = ['clsdecl', 'smartdecl', 'deref']
+    _immutable_fields_ = ['clsdecl', 'smartdecl', 'deref', 'flags']
 
     finalizer_registered = False
 
@@ -1327,6 +1393,7 @@
                  smartdecl=None, deref=rffi.cast(capi.C_METHOD, 0)):
         self.space = space
         self.clsdecl = decl
+        assert isinstance(self.clsdecl, W_CPPClassDecl)
         assert lltype.typeOf(rawobject) == capi.C_OBJECT
         assert not isref or rawobject
         self._rawobject = rawobject
@@ -1334,15 +1401,16 @@
         self.flags = 0
         if isref or (smartdecl and deref):
             self.flags |= INSTANCE_FLAGS_IS_REF
+        self.rt_flags = 0
         if python_owns:
-            self.flags |= INSTANCE_FLAGS_PYTHON_OWNS
+            self.rt_flags |= INSTANCE_FLAGS_PYTHON_OWNS
             self._opt_register_finalizer()
         self.smartdecl = smartdecl
         self.deref     = deref
 
     def _opt_register_finalizer(self):
         if not self.finalizer_registered and not hasattr(self.space, "fake"):
-            assert self.flags & INSTANCE_FLAGS_PYTHON_OWNS
+            assert self.rt_flags & INSTANCE_FLAGS_PYTHON_OWNS
             self.register_finalizer(self.space)
             self.finalizer_registered = True
 


More information about the pypy-commit mailing list