[pypy-commit] pypy unicode-utf8-py3: merge py3.5 into branch

mattip pypy.commits at gmail.com
Sun Jul 8 00:17:52 EDT 2018


Author: Matti Picus <matti.picus at gmail.com>
Branch: unicode-utf8-py3
Changeset: r94827:7cba2470321a
Date: 2018-07-07 21:16 -0700
http://bitbucket.org/pypy/pypy/changeset/7cba2470321a/

Log:	merge py3.5 into branch

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
@@ -566,7 +566,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
@@ -580,12 +580,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_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/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/_cppyy/converter.py b/pypy/module/_cppyy/converter.py
--- a/pypy/module/_cppyy/converter.py
+++ b/pypy/module/_cppyy/converter.py
@@ -82,10 +82,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 +107,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 +124,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
 
 
@@ -172,7 +171,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,
@@ -208,7 +207,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 +227,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 +252,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 +269,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 +299,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 +344,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 +377,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 +389,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 +419,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)
 
@@ -452,37 +448,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
@@ -508,14 +506,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))
 
@@ -539,7 +537,7 @@
 
 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 +549,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:
@@ -574,36 +571,41 @@
         address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
 
 class InstancePtrPtrConverter(InstancePtrConverter):
-    _immutable_fields_ = ['uses_local']
+    typecode = 'o'
 
-    uses_local = True
+    def __init__(self, space, extra):
+        InstancePtrConverter.__init__(self, space, extra)
+        self.ref_buffer = lltype.nullptr(rffi.VOIDPP.TO)
 
-    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))
+    def convert_argument(self, space, w_obj, address):
         x = rffi.cast(rffi.VOIDPP, address)
-        x[0] = rffi.cast(rffi.VOIDP, call_local)
-        address = rffi.cast(capi.C_OBJECT, 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)] = 'o'
+        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):
         # 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 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):
@@ -628,7 +630,7 @@
         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 StdStringRefConverter(InstancePtrConverter):
@@ -646,7 +648,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 +659,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 +673,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 +687,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 +742,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)
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
@@ -166,11 +169,13 @@
 #  W_CPPConstructorOverload:      constructors
 #  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 +188,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 +205,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 +230,55 @@
             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 +337,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 +372,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 +380,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 +395,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):
@@ -466,42 +449,78 @@
         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
+        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):
@@ -576,13 +595,17 @@
     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),
+    __call__   = interp2app(W_CPPOverload.call_args),
     __useffi__ = GetSetProperty(W_CPPOverload.fget_useffi, W_CPPOverload.fset_useffi),
     __doc__    = GetSetProperty(W_CPPOverload.fget_doc)
 )
@@ -593,27 +616,24 @@
 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)
+        #if isinstance(args_w[0], W_CPPInstance):
+            # free function used as bound method, leave in place
         return self.call_impl(capi.C_NULL_OBJECT, args_w)
+        # free functions are implemented as methods of 'namespace' classes, remove 'instance'
+        #return self.call_impl(capi.C_NULL_OBJECT, args_w[1:])
 
     def __repr__(self):
         return "W_CPPStaticOverload(%s)" % [f.prototype() for f in self.functions]
@@ -621,7 +641,7 @@
 W_CPPStaticOverload.typedef = TypeDef(
     'CPPStaticOverload',
     __get__    = interp2app(W_CPPStaticOverload.descr_get),
-    __call__   = interp2app(W_CPPStaticOverload.call),
+    __call__   = interp2app(W_CPPStaticOverload.call_args),
     __useffi__ = GetSetProperty(W_CPPStaticOverload.fget_useffi, W_CPPStaticOverload.fset_useffi),
     __doc__    = GetSetProperty(W_CPPStaticOverload.fget_doc)
 )
@@ -630,27 +650,20 @@
 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):
+    def call_args(self, args_w):
+        jit.promote(self)
         # 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)
+        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
@@ -662,7 +675,7 @@
 W_CPPConstructorOverload.typedef = TypeDef(
     'CPPConstructorOverload',
     __get__    = interp2app(W_CPPConstructorOverload.descr_get),
-    __call__   = interp2app(W_CPPConstructorOverload.call),
+    __call__   = interp2app(W_CPPConstructorOverload.call_args),
     __doc__    = GetSetProperty(W_CPPConstructorOverload.fget_doc)
 )
 
@@ -725,7 +738,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 +763,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 +788,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 +815,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,6 +831,9 @@
     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]
 
@@ -821,7 +841,7 @@
     'CPPTemplateOverload',
     __get__     = interp2app(W_CPPTemplateOverload.descr_get),
     __getitem__ = interp2app(W_CPPTemplateOverload.getitem),
-    __call__    = interp2app(W_CPPTemplateOverload.call),
+    __call__    = interp2app(W_CPPTemplateOverload.call_args),
     __useffi__  = GetSetProperty(W_CPPTemplateOverload.fget_useffi, W_CPPTemplateOverload.fset_useffi),
     __doc__     = GetSetProperty(W_CPPTemplateOverload.fget_doc)
 )
@@ -830,18 +850,18 @@
     """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 +872,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,6 +889,9 @@
     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]
 
@@ -876,7 +899,7 @@
     'CPPTemplateStaticOverload',
     __get__     = interp2app(W_CPPTemplateStaticOverload.descr_get),
     __getitem__ = interp2app(W_CPPTemplateStaticOverload.getitem),
-    __call__    = interp2app(W_CPPTemplateStaticOverload.call),
+    __call__    = interp2app(W_CPPTemplateStaticOverload.call_args),
     __useffi__  = GetSetProperty(W_CPPTemplateStaticOverload.fget_useffi, W_CPPTemplateStaticOverload.fset_useffi),
     __doc__     = GetSetProperty(W_CPPTemplateStaticOverload.fget_doc)
 )
@@ -898,9 +921,9 @@
     _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
 
@@ -1417,7 +1440,7 @@
                     ol = W_CPPStaticOverload(self.space, nss, funcs[:])
                     # TODO: cache this operator (not done yet, as the above does not
                     # select all overloads)
-                    return ol.call([self, w_other])
+                    return ol.call_args([self, w_other])
         except OperationError as e:
             if not e.match(self.space, self.space.w_TypeError):
                 raise
diff --git a/pypy/module/_cppyy/test/test_zjit.py b/pypy/module/_cppyy/test/test_zjit.py
--- a/pypy/module/_cppyy/test/test_zjit.py
+++ b/pypy/module/_cppyy/test/test_zjit.py
@@ -205,6 +205,9 @@
     def exception_match(self, typ, sub):
         return typ is sub
 
+    def is_none(self, w_obj):
+        return w_obj is None
+
     def is_w(self, w_one, w_two):
         return w_one is w_two
 
@@ -268,6 +271,9 @@
     def call_function(self, w_func, *args_w):
         return None
 
+    def call_obj_args(self, w_callable, w_obj, args):
+        return w_callable.call_args([w_obj]+args)
+
     def _freeze_(self):
         return True
 
@@ -283,19 +289,19 @@
         def f():
             cls  = interp_cppyy.scope_byname(space, "example01")
             inst = interp_cppyy._bind_object(space, FakeInt(0), cls, True)
-            cls.get_overload("__init__").descr_get(inst, []).call([FakeInt(0)])
+            cls.get_overload("__init__").descr_get(inst, []).call_args([FakeInt(0)])
             cppmethod = cls.get_overload(method_name)
             assert isinstance(inst, interp_cppyy.W_CPPInstance)
             i = 10
             while i > 0:
                 drv.jit_merge_point(inst=inst, cppmethod=cppmethod, i=i)
-                cppmethod.descr_get(inst, []).call([FakeInt(i)])
+                cppmethod.descr_get(inst, []).call_args([FakeInt(i)])
                 i -= 1
             return 7
         f()
         space = FakeSpace()
         result = self.meta_interp(f, [], listops=True, backendopt=True, listcomp=True)
-        self.check_jitcell_token_count(0)   # same for fast and slow path??
+        self.check_jitcell_token_count(1)
         # rely on replacement of capi calls to raise exception instead (see FakeSpace.__init__)
 
     @py.test.mark.dont_track_allocations("cppmethod.cif_descr kept 'leaks'")
diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py
--- a/pypy/module/sys/test/test_sysmodule.py
+++ b/pypy/module/sys/test/test_sysmodule.py
@@ -358,6 +358,29 @@
             print(ascii(err.getvalue()))
             assert err.getvalue().endswith("ValueError: %s\n" % input)
 
+    def test_excepthook_flushes_stdout(self): r"""
+        import sys, io
+        savestdout = sys.stdout
+        out = io.StringIO()
+        sys.stdout = out
+
+        eh = sys.__excepthook__
+
+        try:
+            raise ValueError(42)
+        except ValueError as exc:
+            print("hello")     # with end-of-line
+            eh(*sys.exc_info())
+        try:
+            raise ValueError(42)
+        except ValueError as exc:
+            print(123, 456, end="")     # no end-of-line here
+            eh(*sys.exc_info())
+
+        sys.stdout = savestdout
+        assert out.getvalue() == 'hello\n123 456'   # no final \n added in 3.x
+        """
+
     # FIXME: testing the code for a lost or replaced excepthook in
     # Python/pythonrun.c::PyErr_PrintEx() is tricky.
 
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -371,20 +371,23 @@
     return wrapint(space, a)
 
 
- at jit.look_inside_iff(lambda space, iv, iw, iz:
-                     jit.isconstant(iw) and jit.isconstant(iz))
 def _pow(space, iv, iw, iz):
     """Helper for pow"""
-    if iw < 0:
-        if iz != 0:
-            raise oefmt(space.w_ValueError,
-                        "pow() 2nd argument cannot be negative when 3rd "
-                        "argument specified")
+    if iz == 0:
+        return _pow_nomod(iv, iw)
+    else:
+        return _pow_mod(space, iv, iw, iz)
+
+ at jit.look_inside_iff(lambda iv, iw: jit.isconstant(iw))
+def _pow_nomod(iv, iw):
+    if iw <= 0:
+        if iw == 0:
+            return 1
         # bounce it, since it always returns float
         raise ValueError
     temp = iv
     ix = 1
-    while iw > 0:
+    while True:
         if iw & 1:
             try:
                 ix = ovfcheck(ix * temp)
@@ -397,12 +400,40 @@
             temp = ovfcheck(temp * temp) # Square the value of temp
         except OverflowError:
             raise
-        if iz:
-            # If we did a multiplication, perform a modulo
-            ix %= iz
-            temp %= iz
-    if iz:
-        ix %= iz
+    return ix
+
+ at jit.look_inside_iff(lambda space, iv, iw, iz:
+                     jit.isconstant(iw) and jit.isconstant(iz))
+def _pow_mod(space, iv, iw, iz):
+    from rpython.rlib.rarithmetic import mulmod
+
+    if iw <= 0:
+        if iw == 0:
+            return 1 % iz   # != 1, for iz == 1 or iz < 0
+        raise oefmt(space.w_ValueError,
+                    "pow() 2nd argument cannot be negative when 3rd "
+                    "argument specified")
+    if iz < 0:
+        try:
+            iz = ovfcheck(-iz)
+        except OverflowError:
+            raise
+        iz_negative = True
+    else:
+        iz_negative = False
+
+    temp = iv
+    ix = 1
+    while True:
+        if iw & 1:
+            ix = mulmod(ix, temp, iz)
+        iw >>= 1   # Shift exponent down by 1 bit
+        if iw == 0:
+            break
+        temp = mulmod(temp, temp, iz)
+
+    if iz_negative and ix > 0:
+        ix -= iz
     return ix
 
 
diff --git a/pypy/objspace/std/test/test_intobject.py b/pypy/objspace/std/test/test_intobject.py
--- a/pypy/objspace/std/test/test_intobject.py
+++ b/pypy/objspace/std/test/test_intobject.py
@@ -1,7 +1,8 @@
 # encoding: utf-8
 import sys
+from pypy.interpreter.error import OperationError
 from pypy.objspace.std import intobject as iobj
-from rpython.rlib.rarithmetic import r_uint, is_valid_int
+from rpython.rlib.rarithmetic import r_uint, is_valid_int, intmask
 from rpython.rlib.rbigint import rbigint
 
 class TestW_IntObject:
@@ -169,6 +170,63 @@
         assert space.isinstance_w(v, space.w_int)
         assert space.bigint_w(v).eq(rbigint.fromlong(pow(10, 20)))
 
+    try:
+        from hypothesis import given, strategies, example
+    except ImportError:
+        pass
+    else:
+        @given(
+           a=strategies.integers(min_value=-sys.maxint-1, max_value=sys.maxint),
+           b=strategies.integers(min_value=-sys.maxint-1, max_value=sys.maxint),
+           c=strategies.integers(min_value=-sys.maxint-1, max_value=sys.maxint))
+        @example(0, 0, -sys.maxint-1)
+        @example(0, 1, -sys.maxint-1)
+        @example(1, 0, -sys.maxint-1)
+        def test_hypot_pow(self, a, b, c):
+            if c == 0:
+                return
+            #
+            # "pow(a, b, c)": if b < 0, should get an app-level ValueError.
+            # Otherwise, should always work except if c == -maxint-1
+            if b < 0:
+                expected = "app-level ValueError"
+            elif b > 0 and c == -sys.maxint-1:
+                expected = OverflowError
+            else:
+                expected = pow(a, b, c)
+
+            try:
+                result = iobj._pow(self.space, a, b, c)
+            except OperationError as e:
+                assert ('ValueError: pow() 2nd argument cannot be negative '
+                        'when 3rd argument specified' == e.errorstr(self.space))
+                result = "app-level ValueError"
+            except OverflowError:
+                result = OverflowError
+            assert result == expected
+
+        @given(
+           a=strategies.integers(min_value=-sys.maxint-1, max_value=sys.maxint),
+           b=strategies.integers(min_value=-sys.maxint-1, max_value=sys.maxint))
+        def test_hypot_pow_nomod(self, a, b):
+            # "a ** b": detect overflows and ValueErrors
+            if b < 0:
+                expected = ValueError
+            elif b > 128 and not (-1 <= a <= 1):
+                expected = OverflowError
+            else:
+                expected = a ** b
+                if expected != intmask(expected):
+                    expected = OverflowError
+
+            try:
+                result = iobj._pow(self.space, a, b, 0)
+            except ValueError:
+                result = ValueError
+            except OverflowError:
+                result = OverflowError
+            assert result == expected
+
     def test_neg(self):
         space = self.space
         x = 42
diff --git a/rpython/rlib/rarithmetic.py b/rpython/rlib/rarithmetic.py
--- a/rpython/rlib/rarithmetic.py
+++ b/rpython/rlib/rarithmetic.py
@@ -840,6 +840,31 @@
         return z
 
 
+ at specialize.memo()
+def check_support_int128():
+    from rpython.rtyper.lltypesystem import rffi
+    return hasattr(rffi, '__INT128_T')
+
+def mulmod(a, b, c):
+    """Computes (a * b) % c.
+    Assumes c > 0, and returns a nonnegative result.
+    """
+    assert c > 0
+    if LONG_BIT < LONGLONG_BIT:
+        a = r_longlong(a)
+        b = r_longlong(b)
+        return intmask((a * b) % c)
+    elif check_support_int128():
+        a = r_longlonglong(a)
+        b = r_longlonglong(b)
+        return intmask((a * b) % c)
+    else:
+        from rpython.rlib.rbigint import rbigint
+        a = rbigint.fromlong(a)
+        b = rbigint.fromlong(b)
+        return a.mul(b).int_mod(c).toint()
+
+
 # String parsing support
 # ---------------------------
 
diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py
--- a/rpython/rlib/rbigint.py
+++ b/rpython/rlib/rbigint.py
@@ -1,6 +1,7 @@
 from rpython.rlib.rarithmetic import LONG_BIT, intmask, longlongmask, r_uint, r_ulonglong
 from rpython.rlib.rarithmetic import ovfcheck, r_longlong, widen
 from rpython.rlib.rarithmetic import most_neg_value_of_same_type
+from rpython.rlib.rarithmetic import check_support_int128
 from rpython.rlib.rstring import StringBuilder
 from rpython.rlib.debug import make_sure_not_resized, check_regular_int
 from rpython.rlib.objectmodel import we_are_translated, specialize, not_rpython
@@ -10,7 +11,7 @@
 
 import math, sys
 
-SUPPORT_INT128 = hasattr(rffi, '__INT128_T')
+SUPPORT_INT128 = check_support_int128()
 BYTEORDER = sys.byteorder
 
 # note about digit sizes:
diff --git a/rpython/rlib/rvmprof/dummy.py b/rpython/rlib/rvmprof/dummy.py
--- a/rpython/rlib/rvmprof/dummy.py
+++ b/rpython/rlib/rvmprof/dummy.py
@@ -23,4 +23,4 @@
         pass
 
     def stop_sampling(self):
-        pass
+        return -1
diff --git a/rpython/rlib/test/test_rarithmetic.py b/rpython/rlib/test/test_rarithmetic.py
--- a/rpython/rlib/test/test_rarithmetic.py
+++ b/rpython/rlib/test/test_rarithmetic.py
@@ -1,5 +1,6 @@
 from rpython.rtyper.test.tool import BaseRtypingTest
 from rpython.rtyper.test.test_llinterp import interpret
+from rpython.rlib import rarithmetic
 from rpython.rlib.rarithmetic import *
 from rpython.rlib.rstring import ParseStringError, ParseStringOverflowError
 from hypothesis import given, strategies, assume
@@ -731,3 +732,17 @@
     py.test.raises(OverflowError, ovfcheck_int32_sub, 2**30, -2**30)
     assert ovfcheck_int32_mul(-2**16, 2**15) == -2**31
     py.test.raises(OverflowError, ovfcheck_int32_mul, -2**16, -2**15)
+
+ at given(strategies.integers(min_value=-sys.maxint-1, max_value=sys.maxint),
+       strategies.integers(min_value=-sys.maxint-1, max_value=sys.maxint),
+       strategies.integers(min_value=1, max_value=sys.maxint))
+def test_mulmod(a, b, c):
+    assert mulmod(a, b, c) == (a * b) % c
+    #
+    import rpython.rlib.rbigint  # import before patching check_support_int128
+    prev = rarithmetic.check_support_int128
+    try:
+        rarithmetic.check_support_int128 = lambda: False
+        assert mulmod(a, b, c) == (a * b) % c
+    finally:
+        rarithmetic.check_support_int128 = prev
diff --git a/rpython/translator/c/test/test_typed.py b/rpython/translator/c/test/test_typed.py
--- a/rpython/translator/c/test/test_typed.py
+++ b/rpython/translator/c/test/test_typed.py
@@ -962,3 +962,12 @@
         f = self.getcompiled(func, [int])
         res = f(2)
         assert res == 1     # and not 2
+
+    def test_mulmod(self):
+        from rpython.rlib.rarithmetic import mulmod
+
+        def func(a, b, c):
+            return mulmod(a, b, c)
+        f = self.getcompiled(func, [int, int, int])
+        res = f(1192871273, 1837632879, 2001286281)
+        assert res == 1573897320


More information about the pypy-commit mailing list