[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