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

Reply via email to