Author: Devin Jeanpierre <[email protected]>
Branch: cpyext-macros-cast
Changeset: r84392:7c4d5229e521
Date: 2016-05-11 16:10 -0700
http://bitbucket.org/pypy/pypy/changeset/7c4d5229e521/
Log: hg merge default
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -89,3 +89,7 @@
Use the new rgc.FinalizerQueue mechanism to clean up the handling of
``__del__`` methods. Fixes notably issue #2287. (All RPython
subclasses of W_Root need to use FinalizerQueue now.)
+
+.. branch: ufunc-outer
+
+Implement ufunc.outer on numpypy
diff --git a/pypy/interpreter/executioncontext.py
b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -466,6 +466,13 @@
list = self.fired_actions
if list is not None:
self.fired_actions = None
+ # NB. in case there are several actions, we reset each
+ # 'action._fired' to false only when we're about to call
+ # 'action.perform()'. This means that if
+ # 'action.fire()' happens to be called any time before
+ # the corresponding perform(), the fire() has no
+ # effect---which is the effect we want, because
+ # perform() will be called anyway.
for action in list:
action._fired = False
action.perform(ec, frame)
diff --git a/pypy/module/_winreg/interp_winreg.py
b/pypy/module/_winreg/interp_winreg.py
--- a/pypy/module/_winreg/interp_winreg.py
+++ b/pypy/module/_winreg/interp_winreg.py
@@ -14,10 +14,11 @@
space.wrap(message)]))
class W_HKEY(W_Root):
- def __init__(self, hkey):
+ def __init__(self, space, hkey):
self.hkey = hkey
+ self.register_finalizer(space)
- def descr_del(self, space):
+ def _finalize_(self, space):
self.Close(space)
def as_int(self):
@@ -64,7 +65,7 @@
@unwrap_spec(key=int)
def new_HKEY(space, w_subtype, key):
hkey = rffi.cast(rwinreg.HKEY, key)
- return space.wrap(W_HKEY(hkey))
+ return space.wrap(W_HKEY(space, hkey))
descr_HKEY_new = interp2app(new_HKEY)
W_HKEY.typedef = TypeDef(
@@ -91,7 +92,6 @@
__int__ - Converting a handle to an integer returns the Win32 handle.
__cmp__ - Handle objects are compared using the handle value.""",
__new__ = descr_HKEY_new,
- __del__ = interp2app(W_HKEY.descr_del),
__repr__ = interp2app(W_HKEY.descr_repr),
__int__ = interp2app(W_HKEY.descr_int),
__nonzero__ = interp2app(W_HKEY.descr_nonzero),
@@ -480,7 +480,7 @@
ret = rwinreg.RegCreateKey(hkey, subkey, rethkey)
if ret != 0:
raiseWindowsError(space, ret, 'CreateKey')
- return space.wrap(W_HKEY(rethkey[0]))
+ return space.wrap(W_HKEY(space, rethkey[0]))
@unwrap_spec(subkey=str, res=int, sam=rffi.r_uint)
def CreateKeyEx(space, w_hkey, subkey, res=0, sam=rwinreg.KEY_WRITE):
@@ -502,7 +502,7 @@
lltype.nullptr(rwin32.LPDWORD.TO))
if ret != 0:
raiseWindowsError(space, ret, 'CreateKeyEx')
- return space.wrap(W_HKEY(rethkey[0]))
+ return space.wrap(W_HKEY(space, rethkey[0]))
@unwrap_spec(subkey=str)
def DeleteKey(space, w_hkey, subkey):
@@ -549,7 +549,7 @@
ret = rwinreg.RegOpenKeyEx(hkey, subkey, res, sam, rethkey)
if ret != 0:
raiseWindowsError(space, ret, 'RegOpenKeyEx')
- return space.wrap(W_HKEY(rethkey[0]))
+ return space.wrap(W_HKEY(space, rethkey[0]))
@unwrap_spec(index=int)
def EnumValue(space, w_hkey, index):
@@ -688,7 +688,7 @@
ret = rwinreg.RegConnectRegistry(machine, hkey, rethkey)
if ret != 0:
raiseWindowsError(space, ret, 'RegConnectRegistry')
- return space.wrap(W_HKEY(rethkey[0]))
+ return space.wrap(W_HKEY(space, rethkey[0]))
@unwrap_spec(source=unicode)
def ExpandEnvironmentStrings(space, source):
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -203,46 +203,46 @@
# id. Invariant: this variable always contain 0 when the PyPy GIL is
# released. It should also contain 0 when regular RPython code
# executes. In non-cpyext-related code, it will thus always be 0.
-#
+#
# **make_generic_cpy_call():** RPython to C, with the GIL held. Before
# the call, must assert that the global variable is 0 and set the
# current thread identifier into the global variable. After the call,
# assert that the global variable still contains the current thread id,
# and reset it to 0.
-#
+#
# **make_wrapper():** C to RPython; by default assume that the GIL is
# held, but accepts gil="acquire", "release", "around",
# "pygilstate_ensure", "pygilstate_release".
-#
+#
# When a wrapper() is called:
-#
+#
# * "acquire": assert that the GIL is not currently held, i.e. the
# global variable does not contain the current thread id (otherwise,
# deadlock!). Acquire the PyPy GIL. After we acquired it, assert
# that the global variable is 0 (it must be 0 according to the
# invariant that it was 0 immediately before we acquired the GIL,
# because the GIL was released at that point).
-#
+#
# * gil=None: we hold the GIL already. Assert that the current thread
# identifier is in the global variable, and replace it with 0.
-#
+#
# * "pygilstate_ensure": if the global variable contains the current
# thread id, replace it with 0 and set the extra arg to 0. Otherwise,
# do the "acquire" and set the extra arg to 1. Then we'll call
# pystate.py:PyGILState_Ensure() with this extra arg, which will do
# the rest of the logic.
-#
+#
# When a wrapper() returns, first assert that the global variable is
# still 0, and then:
-#
+#
# * "release": release the PyPy GIL. The global variable was 0 up to
# and including at the point where we released the GIL, but afterwards
# it is possible that the GIL is acquired by a different thread very
# quickly.
-#
+#
# * gil=None: we keep holding the GIL. Set the current thread
# identifier into the global variable.
-#
+#
# * "pygilstate_release": if the argument is PyGILState_UNLOCKED,
# release the PyPy GIL; otherwise, set the current thread identifier
# into the global variable. The rest of the logic of
@@ -254,7 +254,7 @@
cpyext_namespace = NameManager('cpyext_')
-class ApiFunction:
+class ApiFunction(object):
def __init__(self, argtypes, restype, callable, error=_NOT_SPECIFIED,
c_name=None, gil=None, result_borrowed=False,
result_is_ll=False):
self.argtypes = argtypes
@@ -292,11 +292,48 @@
def get_wrapper(self, space):
wrapper = getattr(self, '_wrapper', None)
if wrapper is None:
- wrapper = make_wrapper(space, self.callable, self.gil)
- self._wrapper = wrapper
- wrapper.relax_sig_check = True
- if self.c_name is not None:
- wrapper.c_name = cpyext_namespace.uniquename(self.c_name)
+ wrapper = self._wrapper = self._make_wrapper(space)
+ return wrapper
+
+ # Make the wrapper for the cases (1) and (2)
+ def _make_wrapper(self, space):
+ "NOT_RPYTHON"
+ # This logic is obscure, because we try to avoid creating one
+ # big wrapper() function for every callable. Instead we create
+ # only one per "signature".
+
+ argtypesw = zip(self.argtypes,
+ [_name.startswith("w_") for _name in self.argnames])
+ error_value = getattr(self, "error_value", CANNOT_FAIL)
+ if (isinstance(self.restype, lltype.Ptr)
+ and error_value is not CANNOT_FAIL):
+ assert lltype.typeOf(error_value) == self.restype
+ assert not error_value # only support error=NULL
+ error_value = 0 # because NULL is not hashable
+
+ if self.result_is_ll:
+ result_kind = "L"
+ elif self.result_borrowed:
+ result_kind = "B" # note: 'result_borrowed' is ignored if we
also
+ else: # say 'result_is_ll=True' (in this case it's
+ result_kind = "." # up to you to handle refcounting anyway)
+
+ signature = (tuple(argtypesw),
+ self.restype,
+ result_kind,
+ error_value,
+ self.gil)
+
+ cache = space.fromcache(WrapperCache)
+ try:
+ wrapper_gen = cache.wrapper_gens[signature]
+ except KeyError:
+ wrapper_gen = WrapperGen(space, signature)
+ cache.wrapper_gens[signature] = wrapper_gen
+ wrapper = wrapper_gen.make_wrapper(self.callable)
+ wrapper.relax_sig_check = True
+ if self.c_name is not None:
+ wrapper.c_name = cpyext_namespace.uniquename(self.c_name)
return wrapper
DEFAULT_HEADER = 'pypy_decl.h'
@@ -692,7 +729,6 @@
def __init__(self, space):
self.space = space
self.wrapper_gens = {} # {signature: WrapperGen()}
- self.stats = [0, 0]
class WrapperGen(object):
wrapper_second_level = None
@@ -718,48 +754,6 @@
return wrapper
-# Make the wrapper for the cases (1) and (2)
-def make_wrapper(space, callable, gil=None):
- "NOT_RPYTHON"
- # This logic is obscure, because we try to avoid creating one
- # big wrapper() function for every callable. Instead we create
- # only one per "signature".
-
- argnames = callable.api_func.argnames
- argtypesw = zip(callable.api_func.argtypes,
- [_name.startswith("w_") for _name in argnames])
- error_value = getattr(callable.api_func, "error_value", CANNOT_FAIL)
- if (isinstance(callable.api_func.restype, lltype.Ptr)
- and error_value is not CANNOT_FAIL):
- assert lltype.typeOf(error_value) == callable.api_func.restype
- assert not error_value # only support error=NULL
- error_value = 0 # because NULL is not hashable
-
- if callable.api_func.result_is_ll:
- result_kind = "L"
- elif callable.api_func.result_borrowed:
- result_kind = "B" # note: 'result_borrowed' is ignored if we also
- else: # say 'result_is_ll=True' (in this case it's
- result_kind = "." # up to you to handle refcounting anyway)
-
- signature = (tuple(argtypesw),
- callable.api_func.restype,
- result_kind,
- error_value,
- gil)
-
- cache = space.fromcache(WrapperCache)
- cache.stats[1] += 1
- try:
- wrapper_gen = cache.wrapper_gens[signature]
- except KeyError:
- #print signature
- wrapper_gen = cache.wrapper_gens[signature] = WrapperGen(space,
- signature)
- cache.stats[0] += 1
- #print 'Wrapper cache [wrappers/total]:', cache.stats
- return wrapper_gen.make_wrapper(callable)
-
@dont_inline
def deadlock_error(funcname):
@@ -1032,7 +1026,7 @@
structindex = {}
for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
for name, func in header_functions.iteritems():
- if not func:
+ if not func:
# added only for the macro, not the decl
continue
restype, args = c_function_signature(db, func)
@@ -1046,7 +1040,7 @@
RPY_EXTERN struct PyPyAPI* pypyAPI = &_pypyAPI;
""" % dict(members=structmembers)
- functions = generate_decls_and_callbacks(db, export_symbols,
+ functions = generate_decls_and_callbacks(db, export_symbols,
prefix='cpyexttest')
global_objects = []
@@ -1428,7 +1422,7 @@
generate_macros(export_symbols, prefix=prefix)
- functions = generate_decls_and_callbacks(db, [], api_struct=False,
+ functions = generate_decls_and_callbacks(db, [], api_struct=False,
prefix=prefix)
code = "#include <Python.h>\n"
if use_micronumpy:
@@ -1484,7 +1478,7 @@
if not func:
continue
newname = mangle_name('PyPy', name) or name
- deco = entrypoint_lowlevel("cpyext", func.argtypes, newname,
+ deco = entrypoint_lowlevel("cpyext", func.argtypes, newname,
relax=True)
deco(func.get_wrapper(space))
diff --git a/pypy/module/cpyext/ndarrayobject.py
b/pypy/module/cpyext/ndarrayobject.py
--- a/pypy/module/cpyext/ndarrayobject.py
+++ b/pypy/module/cpyext/ndarrayobject.py
@@ -26,6 +26,8 @@
ARRAY_CARRAY = ARRAY_C_CONTIGUOUS | ARRAY_BEHAVED
ARRAY_DEFAULT = ARRAY_CARRAY
+npy_intpp = rffi.CArrayPtr(Py_ssize_t)
+
HEADER = 'pypy_numpy.h'
@cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL, header=HEADER)
@@ -196,15 +198,15 @@
order=order, owning=owning, w_subtype=w_subtype)
-@cpython_api([Py_ssize_t, rffi.LONGP, Py_ssize_t], PyObject, header=HEADER)
+@cpython_api([Py_ssize_t, npy_intpp, Py_ssize_t], PyObject, header=HEADER)
def _PyArray_SimpleNew(space, nd, dims, typenum):
return simple_new(space, nd, dims, typenum)
-@cpython_api([Py_ssize_t, rffi.LONGP, Py_ssize_t, rffi.VOIDP], PyObject,
header=HEADER)
+@cpython_api([Py_ssize_t, npy_intpp, Py_ssize_t, rffi.VOIDP], PyObject,
header=HEADER)
def _PyArray_SimpleNewFromData(space, nd, dims, typenum, data):
return simple_new_from_data(space, nd, dims, typenum, data, owning=False)
-@cpython_api([Py_ssize_t, rffi.LONGP, Py_ssize_t, rffi.VOIDP], PyObject,
header=HEADER)
+@cpython_api([Py_ssize_t, npy_intpp, Py_ssize_t, rffi.VOIDP], PyObject,
header=HEADER)
def _PyArray_SimpleNewFromDataOwning(space, nd, dims, typenum, data):
# Variant to take over ownership of the memory, equivalent to:
# PyObject *arr = PyArray_SimpleNewFromData(nd, dims, typenum, data);
@@ -212,7 +214,7 @@
return simple_new_from_data(space, nd, dims, typenum, data, owning=True)
-@cpython_api([rffi.VOIDP, Py_ssize_t, rffi.LONGP, Py_ssize_t, rffi.LONGP,
+@cpython_api([rffi.VOIDP, Py_ssize_t, npy_intpp, Py_ssize_t, npy_intpp,
rffi.VOIDP, Py_ssize_t, Py_ssize_t, PyObject], PyObject, header=HEADER)
def _PyArray_New(space, subtype, nd, dims, typenum, strides, data, itemsize,
flags, obj):
if strides:
diff --git a/pypy/module/cpyext/test/test_translate.py
b/pypy/module/cpyext/test/test_translate.py
--- a/pypy/module/cpyext/test/test_translate.py
+++ b/pypy/module/cpyext/test/test_translate.py
@@ -11,11 +11,11 @@
FT = lltype.FuncType([], lltype.Signed)
FTPTR = lltype.Ptr(FT)
- def make_wrapper(space, func, gil=None):
+ def make_wrapper(self, space):
def wrapper():
- return func(space)
+ return self.callable(space)
return wrapper
- monkeypatch.setattr(pypy.module.cpyext.api, 'make_wrapper', make_wrapper)
+ monkeypatch.setattr(pypy.module.cpyext.api.ApiFunction, '_make_wrapper',
make_wrapper)
@specialize.memo()
def get_tp_function(space, typedef):
diff --git a/pypy/module/cpyext/test/test_typeobject.py
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -1,3 +1,4 @@
+from pypy.interpreter import gateway
from rpython.rtyper.lltypesystem import rffi
from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
from pypy.module.cpyext.test.test_api import BaseApiTest
@@ -391,6 +392,14 @@
api.Py_DecRef(ref)
class AppTestSlots(AppTestCpythonExtensionBase):
+ def setup_class(cls):
+ AppTestCpythonExtensionBase.setup_class.im_func(cls)
+ def _check_type_object(w_X):
+ assert w_X.is_cpytype()
+ assert not w_X.is_heaptype()
+ cls.w__check_type_object = cls.space.wrap(
+ gateway.interp2app(_check_type_object))
+
def test_some_slots(self):
module = self.import_extension('foo', [
("test_type", "METH_O",
@@ -1023,3 +1032,56 @@
break
self.debug_collect()
assert module.getCounter() == 7070
+
+ def test_tp_call_reverse(self):
+ module = self.import_extension('foo', [
+ ("new_obj", "METH_NOARGS",
+ '''
+ PyObject *obj;
+ Foo_Type.tp_flags = Py_TPFLAGS_DEFAULT;
+ Foo_Type.tp_call = &my_tp_call;
+ if (PyType_Ready(&Foo_Type) < 0) return NULL;
+ obj = PyObject_New(PyObject, &Foo_Type);
+ return obj;
+ '''
+ )],
+ '''
+ static PyObject *
+ my_tp_call(PyObject *self, PyObject *args, PyObject *kwds)
+ {
+ return PyInt_FromLong(42);
+ }
+ static PyTypeObject Foo_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "foo.foo",
+ };
+ ''')
+ x = module.new_obj()
+ assert x() == 42
+ assert x(4, bar=5) == 42
+
+ def test_custom_metaclass(self):
+ module = self.import_extension('foo', [
+ ("getMetaClass", "METH_NOARGS",
+ '''
+ PyObject *obj;
+ FooType_Type.tp_flags = Py_TPFLAGS_DEFAULT;
+ FooType_Type.tp_base = &PyType_Type;
+ if (PyType_Ready(&FooType_Type) < 0) return NULL;
+ Py_INCREF(&FooType_Type);
+ return (PyObject *)&FooType_Type;
+ '''
+ )],
+ '''
+ static PyTypeObject FooType_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "foo.Type",
+ };
+ ''')
+ FooType = module.getMetaClass()
+ if not self.runappdirect:
+ self._check_type_object(FooType)
+ class X(object):
+ __metaclass__ = FooType
+ print repr(X)
+ X()
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -405,8 +405,7 @@
W_TypeObject.__init__(self, space, name,
bases_w or [space.w_object], dict_w, force_new_layout=new_layout)
- if not space.is_true(space.issubtype(self, space.w_type)):
- self.flag_cpytype = True
+ self.flag_cpytype = True
self.flag_heaptype = False
# if a sequence or a mapping, then set the flag to force it
if pto.c_tp_as_sequence and pto.c_tp_as_sequence.c_sq_item:
diff --git a/pypy/module/micronumpy/ndarray.py
b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -443,7 +443,7 @@
'array does not have imaginary part to set')
self.implementation.set_imag(space, self, w_value)
- def reshape(self, space, w_shape, order):
+ def reshape(self, space, w_shape, order=NPY.ANYORDER):
new_shape = get_shape_from_iterable(space, self.get_size(), w_shape)
new_impl = self.implementation.reshape(self, new_shape, order)
if new_impl is not None:
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py
b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -1480,7 +1480,21 @@
def test_outer(self):
import numpy as np
- from numpy import absolute
+ c = np.multiply.outer([1, 2, 3], [4, 5, 6])
+ assert c.shape == (3, 3)
+ assert (c ==[[ 4, 5, 6],
+ [ 8, 10, 12],
+ [12, 15, 18]]).all()
+ A = np.array([[1, 2, 3], [4, 5, 6]])
+ B = np.array([[1, 2, 3, 4]])
+ c = np.multiply.outer(A, B)
+ assert c.shape == (2, 3, 1, 4)
+ assert (c == [[[[ 1, 2, 3, 4]],
+ [[ 2, 4, 6, 8]],
+ [[ 3, 6, 9, 12]]],
+ [[[ 4, 8, 12, 16]],
+ [[ 5, 10, 15, 20]],
+ [[ 6, 12, 18, 24]]]]).all()
exc = raises(ValueError, np.absolute.outer, [-1, -2])
assert exc.value[0] == 'outer product only supported for binary
functions'
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -363,12 +363,18 @@
out = space.call_method(obj, '__array_wrap__', out,
space.w_None)
return out
- def descr_outer(self, space, __args__):
- return self._outer(space, __args__)
-
- def _outer(self, space, __args__):
- raise oefmt(space.w_ValueError,
+ def descr_outer(self, space, args_w):
+ if self.nin != 2:
+ raise oefmt(space.w_ValueError,
"outer product only supported for binary functions")
+ if len(args_w) != 2:
+ raise oefmt(space.w_ValueError,
+ "exactly two arguments expected")
+ args = [convert_to_array(space, w_obj) for w_obj in args_w]
+ w_outshape = [space.wrap(i) for i in args[0].get_shape() +
[1]*args[1].ndims()]
+ args0 = args[0].reshape(space, space.newtuple(w_outshape))
+ return self.descr_call(space, Arguments.frompacked(space,
+ space.newlist([args0,
args[1]])))
def parse_kwargs(self, space, kwds_w):
w_casting = kwds_w.pop('casting', None)
@@ -1521,7 +1527,8 @@
# Instantiated in cpyext/ndarrayobject. It is here since ufunc calls
# set_dims_and_steps, otherwise ufunc, ndarrayobject would have circular
# imports
-npy_intpp = rffi.INTPTR_T
+Py_ssize_t = lltype.Typedef(rffi.SSIZE_T, 'Py_ssize_t')
+npy_intpp = rffi.CArrayPtr(Py_ssize_t)
LONG_SIZE = LONG_BIT / 8
CCHARP_SIZE = _get_bitsize('P') / 8
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -568,14 +568,14 @@
# set up extra stuff for PYPY_GC_DEBUG.
MovingGCBase.post_setup(self)
if self.DEBUG and llarena.has_protect:
- # gc debug mode: allocate 23 nurseries instead of just 1,
+ # gc debug mode: allocate 7 nurseries instead of just 1,
# and use them alternatively, while mprotect()ing the unused
# ones to detect invalid access.
debug_start("gc-debug")
self.debug_rotating_nurseries = lltype.malloc(
- NURSARRAY, 22, flavor='raw', track_allocation=False)
+ NURSARRAY, 6, flavor='raw', track_allocation=False)
i = 0
- while i < 22:
+ while i < 6:
nurs = self._alloc_nursery()
llarena.arena_protect(nurs, self._nursery_memory_size(), True)
self.debug_rotating_nurseries[i] = nurs
@@ -1731,7 +1731,6 @@
llarena.arena_reset(prev, pinned_obj_size, 3)
else:
llarena.arena_reset(prev, pinned_obj_size, 0)
- # XXX: debug_rotate_nursery missing here
#
# clean up object's flags
obj = cur + size_gc_header
@@ -1747,6 +1746,8 @@
# reset everything after the last pinned object till the end of the
arena
if self.gc_nursery_debug:
llarena.arena_reset(prev, self.nursery + self.nursery_size - prev,
3)
+ if not nursery_barriers.non_empty(): # no pinned objects
+ self.debug_rotate_nursery()
else:
llarena.arena_reset(prev, self.nursery + self.nursery_size - prev,
0)
#
@@ -1756,7 +1757,6 @@
self.nursery_barriers = nursery_barriers
self.surviving_pinned_objects.delete()
#
- # XXX gc-minimark-pinning does a debug_rotate_nursery() here (groggi)
self.nursery_free = self.nursery
self.nursery_top = self.nursery_barriers.popleft()
#
diff --git a/rpython/rlib/test/test_rmmap.py b/rpython/rlib/test/test_rmmap.py
--- a/rpython/rlib/test/test_rmmap.py
+++ b/rpython/rlib/test/test_rmmap.py
@@ -296,7 +296,7 @@
f = open(self.tmpname + "l2", "w+")
f.write("foobar")
f.flush()
- m = mmap.mmap(f.fileno(), 6, prot=~mmap.PROT_WRITE)
+ m = mmap.mmap(f.fileno(), 6, prot=mmap.PROT_READ|mmap.PROT_EXEC)
py.test.raises(RTypeError, m.check_writeable)
py.test.raises(RTypeError, m.check_writeable)
m.close()
diff --git a/rpython/rtyper/lltypesystem/rffi.py
b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -475,7 +475,7 @@
TYPES += ['signed char', 'unsigned char',
'long long', 'unsigned long long',
'size_t', 'time_t', 'wchar_t',
- 'uintptr_t', 'intptr_t',
+ 'uintptr_t', 'intptr_t', # C note: these two are _integer_ types
'void*'] # generic pointer type
# This is a bit of a hack since we can't use rffi_platform here.
diff --git a/rpython/tool/algo/test/test_regalloc.py
b/rpython/tool/algo/test/test_regalloc.py
new file mode 100644
--- /dev/null
+++ b/rpython/tool/algo/test/test_regalloc.py
@@ -0,0 +1,60 @@
+from rpython.rtyper.test.test_llinterp import gengraph
+from rpython.rtyper.lltypesystem import lltype
+from rpython.tool.algo.regalloc import perform_register_allocation
+from rpython.flowspace.model import Variable
+from rpython.conftest import option
+
+
+def is_int(v):
+ return v.concretetype == lltype.Signed
+
+def check_valid(graph, regalloc, consider_var):
+ if getattr(option, 'view', False):
+ graph.show()
+ num_renamings = 0
+ for block in graph.iterblocks():
+ inputs = [v for v in block.inputargs if consider_var(v)]
+ colors = [regalloc.getcolor(v) for v in inputs]
+ print inputs, ':', colors
+ assert len(inputs) == len(set(colors))
+ in_use = dict(zip(colors, inputs))
+ for op in block.operations:
+ for v in op.args:
+ if isinstance(v, Variable) and consider_var(v):
+ assert in_use[regalloc.getcolor(v)] is v
+ if consider_var(op.result):
+ in_use[regalloc.getcolor(op.result)] = op.result
+ for link in block.exits:
+ for i, v in enumerate(link.args):
+ if consider_var(v):
+ assert in_use[regalloc.getcolor(v)] is v
+ w = link.target.inputargs[i]
+ if regalloc.getcolor(v) is not regalloc.getcolor(w):
+ print '\trenaming %s:%d -> %s:%d' % (
+ v, regalloc.getcolor(v), w, regalloc.getcolor(w))
+ num_renamings += 1
+ return num_renamings
+
+
+def test_loop_1():
+ def f(a, b):
+ while a > 0:
+ b += a
+ a -= 1
+ return b
+ t, rtyper, graph = gengraph(f, [int, int], viewbefore=False)
+ regalloc = perform_register_allocation(graph, is_int)
+ num_renamings = check_valid(graph, regalloc, is_int)
+ assert num_renamings == 0
+
+def test_loop_2():
+ def f(a, b):
+ while a > 0:
+ b += a
+ if b < 10:
+ a, b = b, a
+ a -= 1
+ return b
+ t, rtyper, graph = gengraph(f, [int, int], viewbefore=False)
+ regalloc = perform_register_allocation(graph, is_int)
+ check_valid(graph, regalloc, is_int)
diff --git a/rpython/translator/c/src/int.h b/rpython/translator/c/src/int.h
--- a/rpython/translator/c/src/int.h
+++ b/rpython/translator/c/src/int.h
@@ -53,7 +53,21 @@
/* addition, subtraction */
#define OP_INT_ADD(x,y,r) r = (x) + (y)
+#define OP_INT_SUB(x,y,r) r = (x) - (y)
+#define OP_INT_MUL(x,y,r) r = (x) * (y)
+
+#ifdef __GNUC__
+# if __GNUC__ >= 5
+# define HAVE_BUILTIN_OVERFLOW
+# elif defined(__has_builtin) /* clang */
+# if __has_builtin(__builtin_mul_overflow)
+# define HAVE_BUILTIN_OVERFLOW
+# endif
+# endif
+#endif
+
+#ifndef HAVE_BUILTIN_OVERFLOW
/* cast to avoid undefined behaviour on overflow */
#define OP_INT_ADD_OVF(x,y,r) \
r = (Signed)((Unsigned)x + y); \
@@ -63,14 +77,10 @@
r = (Signed)((Unsigned)x + y); \
if ((r&~x) < 0) FAIL_OVF("integer addition")
-#define OP_INT_SUB(x,y,r) r = (x) - (y)
-
#define OP_INT_SUB_OVF(x,y,r) \
r = (Signed)((Unsigned)x - y); \
if ((r^x) < 0 && (r^~y) < 0) FAIL_OVF("integer subtraction")
-#define OP_INT_MUL(x,y,r) r = (x) * (y)
-
#if SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG && !defined(_WIN64)
#define OP_INT_MUL_OVF(x,y,r) \
{ \
@@ -83,6 +93,17 @@
r = op_llong_mul_ovf(x, y) /* long == long long */
#endif
+#else /* HAVE_BUILTIN_OVERFLOW */
+#define OP_INT_ADD_NONNEG_OVF(x,y,r) OP_INT_ADD_OVF(x,y,r)
+#define OP_INT_ADD_OVF(x,y,r) \
+ if (__builtin_add_overflow(x, y, &r)) FAIL_OVF("integer addition")
+#define OP_INT_SUB_OVF(x,y,r) \
+ if (__builtin_sub_overflow(x, y, &r)) FAIL_OVF("integer subtraction")
+#define OP_INT_MUL_OVF(x,y,r) \
+ if (__builtin_mul_overflow(x, y, &r)) FAIL_OVF("integer multiplication")
+#endif
+
+
/* shifting */
/* NB. shifting has same limitations as C: the shift count must be
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit