[pypy-commit] pypy py3.5-ssl: merge py3.5

plan_rich pypy.commits at gmail.com
Thu Dec 1 06:51:53 EST 2016


Author: Richard Plangger <planrichi at gmail.com>
Branch: py3.5-ssl
Changeset: r88788:c75ec5f968ae
Date: 2016-12-01 12:51 +0100
http://bitbucket.org/pypy/pypy/changeset/c75ec5f968ae/

Log:	merge py3.5

diff --git a/lib-python/3/distutils/sysconfig_pypy.py b/lib-python/3/distutils/sysconfig_pypy.py
--- a/lib-python/3/distutils/sysconfig_pypy.py
+++ b/lib-python/3/distutils/sysconfig_pypy.py
@@ -60,6 +60,8 @@
 
 def _init_posix():
     """Initialize the module as appropriate for POSIX systems."""
+    so_list = [s[0] for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION]
+    so_ext = (so_list or ['.so'])[0]
     g = {}
     g['CC'] = "gcc -pthread"
     g['CXX'] = "g++ -pthread"
@@ -67,7 +69,7 @@
     g['CFLAGS'] = "-DNDEBUG -O2"
     g['CCSHARED'] = "-fPIC"
     g['LDSHARED'] = "gcc -pthread -shared"
-    g['SO'] = [s[0] for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION][0]
+    g['SO'] = so_ext
     g['SHLIB_SUFFIX'] = g['SO']
     g['AR'] = "ar"
     g['ARFLAGS'] = "rc"
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -192,6 +192,14 @@
                 assert self._finalize_.im_func is not W_Root._finalize_.im_func
             space.finalizer_queue.register_finalizer(self)
 
+    def may_unregister_rpython_finalizer(self, space):
+        """Optimization hint only: if there is no user-defined __del__()
+        method, pass the hint ``don't call any finalizer'' to rgc.
+        """
+        if not self.getclass(space).hasuserdel:
+            from rpython.rlib import rgc
+            rgc.may_ignore_finalizer(self)
+
     # hooks that the mapdict implementations needs:
     def _get_mapdict_map(self):
         return None
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -3,7 +3,7 @@
 from pypy.interpreter.pyopcode import LoopBlock, SApplicationException, Yield
 from pypy.interpreter.pycode import CO_YIELD_INSIDE_TRY
 from pypy.interpreter.astcompiler import consts
-from rpython.rlib import jit
+from rpython.rlib import jit, rgc
 from rpython.rlib.objectmodel import specialize
 from rpython.rlib.rarithmetic import r_uint
 
@@ -20,7 +20,7 @@
         self.running = False
         self._name = name           # may be null, use get_name()
         self._qualname = qualname   # may be null, use get_qualname()
-        if (isinstance(self, Coroutine)    # XXX would be cool not to need this
+        if (isinstance(self, Coroutine)
                 or self.pycode.co_flags & CO_YIELD_INSIDE_TRY):
             self.register_finalizer(self.space)
         self.saved_operr = None
@@ -89,7 +89,7 @@
 
         # if the frame is now marked as finished, it was RETURNed from
         if frame.frame_finished_execution:
-            self.frame = None
+            self.frame_is_finished()
             if space.is_w(w_result, space.w_None):
                 raise OperationError(space.w_StopIteration, space.w_None)
             else:
@@ -107,6 +107,14 @@
         if self.saved_operr is not None:
             ec.set_sys_exc_info(self.saved_operr)
             self.saved_operr = None
+        #
+        # Optimization only: after we've started a Coroutine without
+        # CO_YIELD_INSIDE_TRY, then Coroutine._finalize_() will be a no-op
+        if (isinstance(self, Coroutine)
+                and frame.last_instr == -1
+                and not (self.pycode.co_flags & CO_YIELD_INSIDE_TRY)):
+            rgc.may_ignore_finalizer(self)
+        #
         self.running = True
         try:
             w_result = frame.execute_frame(self, w_arg_or_err)
@@ -116,7 +124,7 @@
                 if e.match(space, space.w_StopIteration):
                     self._leak_stopiteration(e)
             finally:
-                self.frame = None
+                self.frame_is_finished()
             raise
         finally:
             frame.f_backref = jit.vref_None
@@ -323,6 +331,10 @@
                     break
                 block = block.previous
 
+    def frame_is_finished(self):
+        self.frame = None
+        rgc.may_ignore_finalizer(self)
+
 
 class GeneratorIterator(GeneratorOrCoroutine):
     "An iterator created by a generator."
@@ -364,7 +376,7 @@
                     break
                 # if the frame is now marked as finished, it was RETURNed from
                 if frame.frame_finished_execution:
-                    self.frame = None
+                    self.frame_is_finished()
                     break
                 results.append(w_result)     # YIELDed
         return unpack_into
diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py
--- a/pypy/interpreter/module.py
+++ b/pypy/interpreter/module.py
@@ -121,31 +121,8 @@
         return space.newtuple(tup_return)
 
     def descr_module__repr__(self, space):
-        w_loader = space.finditem(self.w_dict, space.wrap('__loader__'))
-        if w_loader is not None:
-            try:
-                return space.call_method(w_loader, "module_repr", self)
-            except OperationError:
-                pass
-        try:
-            w_name = space.getattr(self, space.wrap('__name__'))
-            name = space.unicode_w(space.repr(w_name))
-        except OperationError:
-            name = u"'?'"
-
-        try:
-            w___file__ = space.getattr(self, space.wrap('__file__'))
-        except OperationError:
-            w___file__ = space.w_None
-        if not space.isinstance_w(w___file__, space.w_unicode):
-            if w_loader is not None:
-                w_loader_repr = space.unicode_w(space.repr(w_loader))
-                return space.wrap(u"<module %s (%s)>" % (name, w_loader_repr))
-            else:
-                return space.wrap(u"<module %s>" % (name,))
-        else:
-            __file__ = space.unicode_w(space.repr(w___file__))
-            return space.wrap(u"<module %s from %s>" % (name, __file__))
+        w_importlib = space.getbuiltinmodule('_frozen_importlib')
+        return space.call_method(w_importlib, "_module_repr", self)
 
     def descr_getattribute(self, space, w_attr):
         from pypy.objspace.descroperation import object_getattribute
diff --git a/pypy/interpreter/test/test_module.py b/pypy/interpreter/test/test_module.py
--- a/pypy/interpreter/test/test_module.py
+++ b/pypy/interpreter/test/test_module.py
@@ -129,6 +129,20 @@
         expected_repr = "<module 'test_module' ({})>".format(loader_repr)
         assert mod_repr == expected_repr
 
+    def test_repr_with_loader_with_raising_module_repr2(self):
+        import sys
+        test_module = type(sys)("test_module", "doc")
+        # If an exception occurs in module_repr(), the exception is caught
+        # and discarded, and the calculation of the module’s repr continues
+        # as if module_repr() did not exist.
+        class CustomLoaderWithRaisingRepr:
+            @classmethod
+            def module_repr(cls, module):
+                raise KeyboardInterrupt
+
+        test_module.__loader__ = CustomLoaderWithRaisingRepr
+        raises(KeyboardInterrupt, 'repr(test_module)')
+
     def test_repr_with_raising_loader_and___file__(self):
         import sys
         test_module = type(sys)("test_module", "doc")
diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py
--- a/pypy/module/__builtin__/descriptor.py
+++ b/pypy/module/__builtin__/descriptor.py
@@ -1,3 +1,4 @@
+from rpython.rlib import jit
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.gateway import WrappedDefault, interp2app, unwrap_spec
@@ -67,29 +68,43 @@
         # fallback to object.__getattribute__()
         return space.call_function(object_getattribute(space), self, w_name)
 
-def _super_from_frame(space, frame):
-    """super() without args -- fill in from __class__ and first local
-    variable on the stack.
-    """
-    code = frame.pycode
-    if not code:
-        raise oefmt(space.w_RuntimeError, "super(): no code object")
+ at jit.elidable
+def _get_self_location(space, code):
     if code.co_argcount == 0:
         raise oefmt(space.w_RuntimeError, "super(): no arguments")
-    w_obj = frame.locals_cells_stack_w[0]
-    if not w_obj:
-        raise oefmt(space.w_RuntimeError, "super(): arg[0] deleted")
+    args_to_copy = code._args_as_cellvars
+    for i in range(len(args_to_copy)):
+        if args_to_copy[i] == 0:
+            self_cell = i
+            break
+    else:
+        self_cell = -1
 
     for index, name in enumerate(code.co_freevars):
         if name == '__class__':
             break
     else:
         raise oefmt(space.w_RuntimeError, "super(): __class__ cell not found")
+    class_cell = len(code.co_cellvars) + index
+    return self_cell, class_cell
+
+def _super_from_frame(space, frame):
+    """super() without args -- fill in from __class__ and first local
+    variable on the stack.
+    """
+    if frame is None:
+        raise oefmt(space.w_RuntimeError, "super(): no frame object")
+    self_cell, class_cell = _get_self_location(space, frame.getcode())
+    if self_cell < 0:
+        w_obj = frame.locals_cells_stack_w[0]
+    else:
+        w_obj = frame._getcell(self_cell).w_value
+    if not w_obj:
+        raise oefmt(space.w_RuntimeError, "super(): arg[0] deleted")
+
     # a kind of LOAD_DEREF
-    cell = frame._getcell(len(code.co_cellvars) + index)
-    try:
-        w_starttype = cell.get()
-    except ValueError:
+    w_starttype = frame._getcell(class_cell).w_value
+    if w_starttype is None:
         raise oefmt(space.w_RuntimeError, "super(): empty __class__ cell")
     return w_starttype, w_obj
 
diff --git a/pypy/module/__builtin__/test/test_descriptor.py b/pypy/module/__builtin__/test/test_descriptor.py
--- a/pypy/module/__builtin__/test/test_descriptor.py
+++ b/pypy/module/__builtin__/test/test_descriptor.py
@@ -508,4 +508,15 @@
                 del __class__
                 super()
         raises(RuntimeError, X().f)
+        class X:
+            def f(self):
+                def g():
+                    print(self)    # make 'self' a closure inside 'f'
+                del self
+                super()
+        raises(RuntimeError, X().f)
+        class X:
+            def f(*args):
+                super()
+        raises(RuntimeError, X().f)
         """
diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -397,7 +397,7 @@
         space = self.space
         if space.is_none(w_destructor):
             if isinstance(self, W_CDataGCP):
-                self.w_destructor = None
+                self.detach_destructor()
                 return space.w_None
             raise oefmt(space.w_TypeError,
                         "Can remove destructor only on a object "
@@ -604,6 +604,10 @@
             self.w_destructor = None
             self.space.call_function(w_destructor, self.w_original_cdata)
 
+    def detach_destructor(self):
+        self.w_destructor = None
+        self.may_unregister_rpython_finalizer(self.space)
+
 
 W_CData.typedef = TypeDef(
     '_cffi_backend.CData',
diff --git a/pypy/module/_cffi_backend/cdlopen.py b/pypy/module/_cffi_backend/cdlopen.py
--- a/pypy/module/_cffi_backend/cdlopen.py
+++ b/pypy/module/_cffi_backend/cdlopen.py
@@ -55,6 +55,7 @@
         if not libhandle:
             raise oefmt(self.ffi.w_FFIError, "library '%s' is already closed",
                         self.libname)
+        self.may_unregister_rpython_finalizer(self.ffi.space)
 
         # Clear the dict to force further accesses to do cdlopen_fetch()
         # again, and fail because the library was closed.  Note that the
diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py
--- a/pypy/module/_io/interp_bufferedio.py
+++ b/pypy/module/_io/interp_bufferedio.py
@@ -63,15 +63,47 @@
         raise NotImplementedError
 
     def read_w(self, space, w_size=None):
+        """Read and return up to n bytes.
+
+If the argument is omitted, None, or negative, reads and
+returns all data until EOF.
+
+If the argument is positive, and the underlying raw stream is
+not 'interactive', multiple raw reads may be issued to satisfy
+the byte count (unless EOF is reached first).  But for
+interactive raw streams (as well as sockets and pipes), at most
+one raw read will be issued, and a short result does not imply
+that EOF is imminent.
+
+Returns an empty bytes object on EOF.
+
+Returns None if the underlying raw stream was open in non-blocking
+mode and no data is available at the moment."""
         self._unsupportedoperation(space, "read")
 
     def read1_w(self, space, w_size):
+        """Read and return up to n bytes, with at most one read() call
+to the underlying raw stream. A short result does not imply
+that EOF is imminent.
+
+Returns an empty bytes object on EOF."""
         self._unsupportedoperation(space, "read1")
 
     def write_w(self, space, w_data):
+        """Write the given buffer to the IO stream.
+
+Returns the number of bytes written, which is always the length of b
+in bytes.
+
+Raises BlockingIOError if the buffer is full and the
+underlying raw stream cannot accept more data at the moment."""
         self._unsupportedoperation(space, "write")
 
     def detach_w(self, space):
+        """Disconnect this buffer from its underlying raw stream and return it.
+
+After the raw stream has been detached, the buffer is in an unusable
+state."""
         self._unsupportedoperation(space, "detach")
 
     def readinto_w(self, space, w_buffer):
@@ -92,6 +124,20 @@
 
 W_BufferedIOBase.typedef = TypeDef(
     '_io._BufferedIOBase', W_IOBase.typedef,
+    __doc__="""Base class for buffered IO objects.
+
+The main difference with RawIOBase is that the read() method
+supports omitting the size argument, and does not have a default
+implementation that defers to readinto().
+
+In addition, read(), readinto() and write() may raise
+BlockingIOError if the underlying raw stream is in non-blocking
+mode and not ready; unlike their raw counterparts, they will never
+return None.
+
+A typical implementation should not inherit from a RawIOBase
+implementation, but wrap one.
+""",
     __new__ = generic_new_descr(W_BufferedIOBase),
     read = interp2app(W_BufferedIOBase.read_w),
     read1 = interp2app(W_BufferedIOBase.read1_w),
@@ -112,6 +158,9 @@
     def getlength(self):
         return self.length
 
+    def getitem(self, index):
+        return self.buf[index]
+
     def setitem(self, index, char):
         self.buf[self.start + index] = char
 
diff --git a/pypy/module/_io/test/test_bufferedio.py b/pypy/module/_io/test/test_bufferedio.py
--- a/pypy/module/_io/test/test_bufferedio.py
+++ b/pypy/module/_io/test/test_bufferedio.py
@@ -65,6 +65,23 @@
         bufio = _io.BufferedReader(MockIO())
         assert bufio.read(9000) == b"abcdefg"
 
+    def test_valid_buffer(self):
+        import _io
+
+        class MockIO(_io._IOBase):
+            def readable(self):
+                return True
+
+            def readinto(self, buf):
+                # Check that `buf` is a valid memoryview object
+                assert buf.itemsize == 1
+                assert buf.strides == (1,)
+                assert buf.shape == (len(buf),)
+                return len(bytes(buf))
+
+        bufio = _io.BufferedReader(MockIO())
+        assert len(bufio.read(5)) == 5  # Note: PyPy zeros the buffer, CPython does not
+
     def test_buffering(self):
         import _io
         data = b"abcdefghi"
@@ -695,7 +712,7 @@
                 expected[j] = 2
                 expected[i] = 1
                 assert raw.getvalue() == expected
-        
+
     def test_interleaved_read_write(self):
         import _io as io
         # Test for issue #12213
diff --git a/pypy/module/_socket/interp_socket.py b/pypy/module/_socket/interp_socket.py
--- a/pypy/module/_socket/interp_socket.py
+++ b/pypy/module/_socket/interp_socket.py
@@ -216,7 +216,7 @@
     def descr_repr(self, space):
         fd = intmask(self.sock.fd)  # Force to signed type even on Windows.
         return space.wrap("<socket object, fd=%d, family=%d,"
-                          " type=%d, protocol=%d>" %
+                          " type=%d, proto=%d>" %
                           (fd, self.sock.family,
                            self.sock.type, self.sock.proto))
 
@@ -266,6 +266,7 @@
         except SocketError:
             # cpython doesn't return any errors on close
             pass
+        self.may_unregister_rpython_finalizer(space)
 
     def connect_w(self, space, w_addr):
         """connect(address)
diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py
--- a/pypy/module/_socket/test/test_sock_app.py
+++ b/pypy/module/_socket/test/test_sock_app.py
@@ -373,12 +373,12 @@
         import _socket
         s = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
         try:
-            expected = ('<socket object, fd=%s, family=%s, type=%s, protocol=%s>'
+            expected = ('<socket object, fd=%s, family=%s, type=%s, proto=%s>'
                         % (s.fileno(), s.family, s.type, s.proto))
             assert repr(s) == expected
         finally:
             s.close()
-        expected = ('<socket object, fd=-1, family=%s, type=%s, protocol=%s>'
+        expected = ('<socket object, fd=-1, family=%s, type=%s, proto=%s>'
                     % (s.family, s.type, s.proto))
         assert repr(s) == expected
 
diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py
--- a/pypy/module/_weakref/interp__weakref.py
+++ b/pypy/module/_weakref/interp__weakref.py
@@ -218,7 +218,7 @@
             return self.space.w_None
         return w_obj
 
-    def descr__eq__(self, space, w_ref2):
+    def compare(self, space, w_ref2, invert):
         if not isinstance(w_ref2, W_Weakref):
             return space.w_NotImplemented
         ref1 = self
@@ -226,11 +226,18 @@
         w_obj1 = ref1.dereference()
         w_obj2 = ref2.dereference()
         if w_obj1 is None or w_obj2 is None:
-            return space.is_(ref1, ref2)
-        return space.eq(w_obj1, w_obj2)
+            w_res = space.is_(ref1, ref2)
+        else:
+            w_res = space.eq(w_obj1, w_obj2)
+        if invert:
+            w_res = space.not_(w_res)
+        return w_res
+
+    def descr__eq__(self, space, w_ref2):
+        return self.compare(space, w_ref2, invert=False)
 
     def descr__ne__(self, space, w_ref2):
-        return space.not_(space.eq(self, w_ref2))
+        return self.compare(space, w_ref2, invert=True)
 
     def descr_callback(self, space):
         return self.w_callable
diff --git a/pypy/module/_weakref/test/test_weakref.py b/pypy/module/_weakref/test/test_weakref.py
--- a/pypy/module/_weakref/test/test_weakref.py
+++ b/pypy/module/_weakref/test/test_weakref.py
@@ -153,6 +153,14 @@
         assert not (ref1 == [])
         assert ref1 != []
 
+    def test_ne(self):
+        import _weakref
+        class X(object):
+            pass
+        ref1 = _weakref.ref(X())
+        assert ref1.__eq__(X()) is NotImplemented
+        assert ref1.__ne__(X()) is NotImplemented
+
     def test_getweakrefs(self):
         import _weakref, gc
         class A(object):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
@@ -272,11 +272,11 @@
             _write = libc.load_function(BWrite, 'write')
             i = 0
             fd0, fd1 = os.pipe()
-            buffer = _cffi_backend.newp(BCharP, 'A')
+            buffer = _cffi_backend.newp(BCharP, b'A')
             while i < 300:
                 tmp = _write(fd1, buffer, 1)   # ID: cfficall
                 assert tmp == 1
-                assert os.read(fd0, 2) == 'A'
+                assert os.read(fd0, 2) == b'A'
                 i += 1
             os.close(fd0)
             os.close(fd1)
@@ -410,7 +410,7 @@
         i161 = int_lt(i160, i43)
         guard_true(i161, descr=...)
         i162 = int_add(i160, 1)
-        setfield_gc(p22, i162, descr=<FieldS pypy.module.__builtin__.functional.W_XRangeIterator.inst_current .>)
+        setfield_gc(p22, i162, descr=<FieldS pypy.module.__builtin__.functional.W_IntRangeIterator.inst_current .>)
         guard_not_invalidated(descr=...)
         p163 = force_token()
         p164 = force_token()
diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py
--- a/pypy/module/pypyjit/test_pypy_c/test_globals.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py
@@ -16,5 +16,6 @@
         assert log.result == 500
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match_by_id("loadglobal", """
+            p1 = getfield_gc_r(..., descr=...)     # dead
             guard_not_invalidated(descr=...)
         """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py
--- a/pypy/module/pypyjit/test_pypy_c/test_instance.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py
@@ -320,3 +320,36 @@
             --TICK--
             jump(..., descr=...)
         """)
+
+    def test_super_no_args(self):
+        def main():
+            class A(object):
+                def m(self, x):
+                    return x + 1
+            class B(A):
+                def m(self, x):
+                    return super().m(x)
+            i = 0
+            while i < 300:
+                i = B().m(i)
+            return i
+
+        log = self.run(main, [])
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match("""
+            i78 = int_lt(i72, 300)
+            guard_true(i78, descr=...)
+            guard_not_invalidated(descr=...)
+            p1 = force_token()
+            p65 = force_token()
+            p3 = force_token()
+            i81 = int_add(i72, 1)
+
+            # can't use TICK here, because of the extra setfield_gc
+            ticker0 = getfield_raw_i(#, descr=<FieldS pypysig_long_struct.c_value .*>)
+            setfield_gc(p0, p65, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .>)
+            ticker_cond0 = int_lt(ticker0, 0)
+            guard_false(ticker_cond0, descr=...)
+
+            jump(..., descr=...)
+        """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py
--- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py
@@ -38,7 +38,7 @@
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
             ...
-            p76 = call_assembler_r(_, _, _, _, descr=...)
+            p76 = call_assembler_r(..., descr=...)
             ...
         """)
         loop2 = log.loops[0]
@@ -79,6 +79,6 @@
         assert len(guards) < 20
         assert loop.match("""
             ...
-            p76 = call_assembler_r(_, _, _, _, descr=...)
+            p76 = call_assembler_r(..., descr=...)
             ...
         """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -247,6 +247,13 @@
         """)
 
     def test_dont_trace_every_iteration(self):
+        def reference(a, b):
+            i = sa = 0
+            while i < 300:
+                sa += a % b
+                i += 1
+            return sa
+        #
         def main(a, b):
             i = sa = 0
             while i < 300:
@@ -258,9 +265,12 @@
                 i += 1
             return sa
         #
+        log_ref = self.run(reference, [10, 20])
+        assert log_ref.result == 300 * (10 % 20)
+        #
         log = self.run(main, [10, 20])
         assert log.result == 300 * (10 % 20)
-        assert log.jit_summary.tracing_no == 1
+        assert log.jit_summary.tracing_no == log_ref.jit_summary.tracing_no
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
             i11 = int_lt(i7, 300)
@@ -274,7 +284,7 @@
         #
         log = self.run(main, [-10, -20])
         assert log.result == 300 * (-10 % -20)
-        assert log.jit_summary.tracing_no == 1
+        assert log.jit_summary.tracing_no == log_ref.jit_summary.tracing_no
 
     def test_overflow_checking(self):
         """
@@ -297,6 +307,7 @@
         self.run_and_check(main, [])
 
     def test_global(self):
+        # check that the global read is removed even from the entry bridge
         log = self.run("""
         i = 0
         globalinc = 1
@@ -308,7 +319,10 @@
         """, [1000])
 
         loop, = log.loops_by_id("globalread", is_entry_bridge=True)
-        assert len(loop.ops_by_id("globalread")) == 0
+        assert loop.match_by_id("globalread", """
+            # only a dead read
+            p26 = getfield_gc_r(ConstPtr(ptr25), descr=<FieldP pypy.objspace.std.unicodeobject.W_UnicodeObject.inst__utf8 .>)
+        """)
 
     def test_eval(self):
         def main():
@@ -349,7 +363,8 @@
     def test_long_comparison(self):
         def main(n):
             while n:
-                12345L > 123L  # ID: long_op
+                x = 12345678901234567890123456
+                x > 1231231231231231231231231  # ID: long_op
                 n -= 1
 
         log = self.run(main, [300])
diff --git a/pypy/module/pypyjit/test_pypy_c/test_shift.py b/pypy/module/pypyjit/test_pypy_c/test_shift.py
--- a/pypy/module/pypyjit/test_pypy_c/test_shift.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_shift.py
@@ -196,8 +196,7 @@
         """
         from sys import maxint
 
-        def main(a, b, c):
-            from sys import maxint
+        def main(a, b, c, maxint):
             i = sa = 0
             while i < 300:
                 if 0 < a < 10: pass
@@ -210,9 +209,9 @@
                 sa += (b<<100)>>100
                 sa += (c<<100)>>100
                 i += 1
-            return long(sa)
+            return sa
 
         for a in (1, 4, 8, 100):
             for b in (-10, 10, -201, 201, -maxint/3, maxint/3):
                 for c in (-10, 10, -maxint/3, maxint/3):
-                    yield self.run_and_check, main, [a, b, c]
+                    yield self.run_and_check, main, [a, b, c, maxint]
diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py
--- a/pypy/module/pypyjit/test_pypy_c/test_string.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_string.py
@@ -5,50 +5,102 @@
 
 
 class TestString(BaseTestPyPyC):
+
+    def test_python3_missing_bchr(self):
+        # Check that 'bytes([i])' is special-cased into something
+        # efficient, as Python 3.5 doesn't have a bchr() function or
+        # anything more direct.
+        def main(n):
+            i = 0
+            result = b''
+            while i < n:
+                c = bytes([i])
+                result += c
+                i += 1
+            return i
+        log = self.run(main, [255])
+        assert log.result == 255
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match("""
+            # nothing left like allocating a list object or doing any
+            # residual call
+            i49 = int_lt(i38, i26)
+            guard_true(i49, descr=...)
+            guard_not_invalidated(descr=...)
+            i51 = int_lt(i38, 256)
+            guard_true(i51, descr=...)
+            i53 = int_add(i38, 1)
+            --TICK--
+            i58 = strlen(p46)
+            i60 = int_add(i58, 1)
+            p61 = newstr(i60)
+            copystrcontent(p46, p61, 0, 0, i58)
+            strsetitem(p61, i58, i38)
+            p62 = newstr(1)
+            strsetitem(p62, 0, i38)
+            jump(..., descr=...)
+        """)
+
     def test_lookup_default_encoding(self):
         def main(n):
-            import string
             i = 0
-            letters = string.letters
-            uletters = unicode(string.letters)
+            letters = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+            uletters = u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
             while i < n:
-                i += letters[i % len(letters)] == uletters[i % len(letters)]
+                c = bytes([letters[i % len(uletters)]])
+                i += (c.decode() == uletters[i % len(uletters)])
             return i
 
         log = self.run(main, [300], import_site=True)
         assert log.result == 300
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
-            i14 = int_lt(i6, i9)
-            guard_true(i14, descr=...)
+            i88 = int_lt(i83, i36)
+            guard_true(i88, descr=...)
+            p90 = getfield_gc_r(ConstPtr(ptr89), descr=<FieldP pypy.objspace.std.unicodeobject.W_UnicodeObject.inst__utf8 .>)
             guard_not_invalidated(descr=...)
-            i16 = int_eq(i6, %d)
-            i19 = call_i(ConstClass(ll_int_py_mod__Signed_Signed), i6, i10, descr=<Calli . ii EF=0 OS=14>)
-            i21 = int_lt(i19, 0)
-            guard_false(i21, descr=...)
-            i22 = int_ge(i19, i10)
-            guard_false(i22, descr=...)
-            i23 = strgetitem(p11, i19)
-            i24 = int_ge(i19, i12)
-            guard_false(i24, descr=...)
-            i25 = unicodegetitem(p13, i19)
-            p27 = newstr(1)
-            strsetitem(p27, 0, i23)
-            p30 = call_r(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=...)
+            i92 = int_eq(i83, %d)
+            i94 = call_i(ConstClass(ll_int_py_mod__Signed_Signed), i83, i46, descr=<Calli . ii EF=0 OS=14>)
+            i96 = int_lt(i94, 0)
+            guard_false(i96, descr=...)
+            i97 = int_ge(i94, i53)
+            guard_false(i97, descr=...)
+            i98 = strgetitem(p52, i94)
+            p100 = getfield_gc_r(ConstPtr(ptr99), descr=<FieldP pypy.objspace.std.unicodeobject.W_UnicodeObject.inst__utf8 .>)
+            p101 = force_token()
+            p103 = newstr(1)
+            strsetitem(p103, 0, i98)
+            p104 = new(descr=<SizeDescr ..?>)
+            p106 = newunicode(1)
+            setfield_gc(p0, p101, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .>)
+            setfield_gc(p104, p106, descr=<FieldP unicodebuilder.current_buf ..?>)
+            setfield_gc(p104, 0, descr=<FieldS unicodebuilder.current_pos ..?>)
+            setfield_gc(p104, 1, descr=<FieldS unicodebuilder.current_end ..?>)
+            setfield_gc(p104, 1, descr=<FieldS unicodebuilder.total_size 32>)
+            i113 = call_may_force_i(ConstClass(str_decode_utf_8_impl), p103, 1, ConstPtr(null), 1, 0, 0, p104, descr=<Calli . ririiir EF=7>)
+            guard_not_forced(descr=...)
             guard_no_exception(descr=...)
-            i32 = call_i(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=...)
-            guard_true(i32, descr=...)
-            i34 = int_add(i6, 1)
+            p116 = call_r(ConstClass(ll_build_trampoline__v1351___simple_call__function_), p104, descr=<Callr . r EF=5>)
+            guard_no_exception(descr=...)
+            guard_nonnull(p116, descr=...)
+            p118 = getfield_gc_r(ConstPtr(ptr117), descr=<FieldP pypy.objspace.std.unicodeobject.W_UnicodeObject.inst__utf8 .>)
+            guard_not_invalidated(descr=...)
+            i119 = int_ge(i94, i46)
+            guard_false(i119, descr=...)
+            i120 = unicodegetitem(p45, i94)
+            i122 = call_i(ConstClass(_ll_2_str_eq_nonnull_char__rpy_unicodePtr_UniChar), p116, i120, descr=<Calli . ri EF=0 OS=49>)
+            guard_true(i122, descr=...)
+            i124 = int_add(i83, 1)
             --TICK--
             jump(..., descr=...)
         """ % (-sys.maxint-1,))
 
-    def test_long(self):
+    def test_int_base_16(self):
         def main(n):
-            import string
             i = 1
             while i < n:
-                i += int(long(string.digits[i % len(string.digits)], 16))
+                digits = '0123456789'
+                i += int(digits[i % len(digits)], 16)
             return i
 
         log = self.run(main, [1100], import_site=True)
@@ -61,7 +113,9 @@
         assert loop.match("""
             i11 = int_lt(i6, i7)
             guard_true(i11, descr=...)
+            p70 = getfield_gc_r(ConstPtr(ptr69), descr=<FieldP pypy.objspace.std.unicodeobject.W_UnicodeObject.inst__utf8 .>)
             guard_not_invalidated(descr=...)
+            p72 = getfield_gc_r(ConstPtr(ptr71), descr=<FieldP pypy.objspace.std.unicodeobject.W_UnicodeObject.inst__utf8 .>)
             i13 = int_eq(i6, %d)         # value provided below
 
             # "mod 10" block:
@@ -73,17 +127,20 @@
             i87 = int_mul(i85, 10)
             i19 = int_sub(i6, i87)
 
-            i23 = strgetitem(p10, i19)
-            p25 = newstr(1)
-            strsetitem(p25, 0, i23)
-            p93 = call_r(ConstClass(fromstr), p25, 16, descr=<Callr . ri EF=4>)
+            i23 = unicodegetitem(ConstPtr(ptr92), i19)
+            p25 = newunicode(1)
+            unicodesetitem(p25, 0, i23)
+            p97 = call_r(ConstClass(_rpy_unicode_to_decimal_w), p25, descr=<Callr . r EF=5>)
             guard_no_exception(descr=...)
-            i95 = getfield_gc_i(p93, descr=<FieldS rpython.rlib.rbigint.rbigint.inst_size .*>)
-            i96 = int_gt(i95, #)
-            guard_false(i96, descr=...)
-            i94 = call_i(ConstClass(rbigint._toint_helper), p93, descr=<Calli . r EF=4>)
+            i98 = unicodelen(p97)
+            p99 = force_token()
+            setfield_gc(p0, p99, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .>)
+            p104 = call_may_force_r(ConstClass(unicode_encode_utf_8_impl), p97, i98, ConstPtr(ptr101), 1, 1, descr=<Callr . ririi EF=7>)
+            guard_not_forced(descr=...)
             guard_no_exception(descr=...)
-            i95 = int_add_ovf(i6, i94)
+            i107 = call_i(ConstClass(string_to_int), p104, 16, descr=<Calli . ri EF=4>)
+            guard_no_exception(descr=...)
+            i95 = int_add_ovf(i6, i107)
             guard_no_overflow(descr=...)
             --TICK--
             jump(..., descr=...)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_struct.py b/pypy/module/pypyjit/test_pypy_c/test_struct.py
--- a/pypy/module/pypyjit/test_pypy_c/test_struct.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_struct.py
@@ -21,7 +21,7 @@
             while i < n:
                 buf = struct.pack("<i", i)       # ID: pack
                 x = struct.unpack("<i", buf)[0]  # ID: unpack
-                i += x / i
+                i += x // i
             return i
 
         log = self.run(main, [1000])
@@ -82,7 +82,7 @@
             while i < n:
                 buf = s.pack(-1, i)     # ID: pack
                 x = s.unpack(buf)[1]    # ID: unpack
-                i += x / i
+                i += x // i
             return i
 
         log = self.run(main, [1000])
diff --git a/pypy/module/select/interp_epoll.py b/pypy/module/select/interp_epoll.py
--- a/pypy/module/select/interp_epoll.py
+++ b/pypy/module/select/interp_epoll.py
@@ -81,6 +81,7 @@
 
 class W_Epoll(W_Root):
     def __init__(self, space, epfd):
+        self.space = space
         self.epfd = epfd
         self.register_finalizer(space)
 
@@ -113,6 +114,7 @@
         if not self.get_closed():
             socketclose(self.epfd)
             self.epfd = -1
+            self.may_unregister_rpython_finalizer(self.space)
 
     def epoll_ctl(self, space, ctl, w_fd, eventmask, ignore_ebadf=False):
         fd = space.c_filedescriptor_w(w_fd)
diff --git a/pypy/module/select/interp_kqueue.py b/pypy/module/select/interp_kqueue.py
--- a/pypy/module/select/interp_kqueue.py
+++ b/pypy/module/select/interp_kqueue.py
@@ -109,6 +109,7 @@
 
 class W_Kqueue(W_Root):
     def __init__(self, space, kqfd):
+        self.space = space
         self.kqfd = kqfd
         self.register_finalizer(space)
 
@@ -137,6 +138,7 @@
             kqfd = self.kqfd
             self.kqfd = -1
             socketclose_no_errno(kqfd)
+            self.may_unregister_rpython_finalizer(self.space)
 
     def check_closed(self, space):
         if self.get_closed():
diff --git a/pypy/module/signal/test/test_signal.py b/pypy/module/signal/test/test_signal.py
--- a/pypy/module/signal/test/test_signal.py
+++ b/pypy/module/signal/test/test_signal.py
@@ -40,23 +40,22 @@
     }
 
     def setup_class(cls):
-        cls.w_signal = cls.space.getbuiltinmodule('_signal')
         cls.w_temppath = cls.space.wrap(
             str(py.test.ensuretemp("signal").join("foo.txt")))
         cls.w_appdirect = cls.space.wrap(cls.runappdirect)
 
     def test_exported_names(self):
-        import os
-        self.signal.__dict__   # crashes if the interpleveldefs are invalid
+        import os, _signal
+        _signal.__dict__   # crashes if the interpleveldefs are invalid
         if os.name == 'nt':
-            assert self.signal.CTRL_BREAK_EVENT == 1
-            assert self.signal.CTRL_C_EVENT == 0
+            assert _signal.CTRL_BREAK_EVENT == 1
+            assert _signal.CTRL_C_EVENT == 0
 
     def test_basics(self):
-        import types, os
+        import types, os, _signal
         if not hasattr(os, 'kill') or not hasattr(os, 'getpid'):
             skip("requires os.kill() and os.getpid()")
-        signal = self.signal   # the signal module to test
+        signal = _signal   # the signal module to test
         if not hasattr(signal, 'SIGUSR1'):
             skip("requires SIGUSR1 in signal")
         signum = signal.SIGUSR1
diff --git a/pypy/module/sys/app.py b/pypy/module/sys/app.py
--- a/pypy/module/sys/app.py
+++ b/pypy/module/sys/app.py
@@ -112,23 +112,35 @@
 
 
 class SimpleNamespace:
+    """A simple attribute-based namespace.
+
+SimpleNamespace(**kwargs)"""
+
     def __init__(self, **kwargs):
         self.__dict__.update(kwargs)
 
-    def __repr__(self, recurse=set()):
+    def __repr__(self):
         ident = id(self)
-        if ident in recurse:
+        if ident in sns_recurse:
             return "namespace(...)"
-        recurse.add(ident)
+        sns_recurse.add(ident)
         try:
             pairs = ('%s=%r' % item for item in sorted(self.__dict__.items()))
             return "namespace(%s)" % ', '.join(pairs)
         finally:
-            recurse.remove(ident)
+            sns_recurse.discard(ident)
 
     def __eq__(self, other):
-        return (isinstance(other, SimpleNamespace) and
-                self.__dict__ == other.__dict__)
+        if issubclass(type(other), SimpleNamespace):
+            return self.__dict__ == other.__dict__
+        return NotImplemented
+
+    def __ne__(self, other):
+        if issubclass(type(other), SimpleNamespace):
+            return self.__dict__ != other.__dict__
+        return NotImplemented
+
+sns_recurse = set()
 
 # This class is not exposed in sys, but by the types module.
 SimpleNamespace.__module__ = 'types'
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
@@ -589,6 +589,35 @@
         #
         raises(AttributeError, "del ns.spam")
         del ns.y
+        #
+        assert ns == SimpleNamespace(z=4, x=1, w=3)
+        assert (ns != SimpleNamespace(z=4, x=1, w=3)) is False
+        assert (ns == SimpleNamespace(z=4, x=2, w=3)) is False
+        assert ns != SimpleNamespace(z=4, x=2, w=3)
+        #
+        class Foo(SimpleNamespace):
+            pass
+        assert ns == Foo(z=4, x=1, w=3)
+        assert (ns != Foo(z=4, x=1, w=3)) is False
+        assert (ns == Foo(z=4, x=2, w=3)) is False
+        assert ns != Foo(z=4, x=2, w=3)
+        #
+        class Other:
+            def __init__(self, x, z, w):
+                self.x = x
+                self.z = z
+                self.w = w
+        assert (ns == Other(z=4, x=1, w=3)) is False
+        assert ns != Other(z=4, x=1, w=3)
+        assert (Foo(z=4, x=1, w=3) == Other(z=4, x=1, w=3)) is False
+        assert Foo(z=4, x=1, w=3) != Other(z=4, x=1, w=3)
+        #
+        class Fake:
+            __class__ = SimpleNamespace
+        assert isinstance(Fake(), SimpleNamespace)
+        assert not issubclass(Fake, SimpleNamespace)
+        assert (Fake() == SimpleNamespace()) is False
+        assert SimpleNamespace() != Fake()
 
     def test_pickle_simplenamespace(self):
         import pickle, sys
diff --git a/pypy/module/zlib/interp_zlib.py b/pypy/module/zlib/interp_zlib.py
--- a/pypy/module/zlib/interp_zlib.py
+++ b/pypy/module/zlib/interp_zlib.py
@@ -183,6 +183,7 @@
                 if mode == rzlib.Z_FINISH:    # release the data structures now
                     rzlib.deflateEnd(self.stream)
                     self.stream = rzlib.null_stream
+                    self.may_unregister_rpython_finalizer(space)
             finally:
                 self.unlock()
         except rzlib.RZlibError as e:
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -705,7 +705,7 @@
                 return w_result
 
             raise oefmt(space.w_TypeError,
-                        "%(specialname)s returned non-%(targetname)s (type "
+                        "%(specialname)s returned non-string (type "
                         "'%%T')", w_result)
         assert not hasattr(DescrOperation, %(targetname)r)
         DescrOperation.%(targetname)s = %(targetname)s
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -66,15 +66,16 @@
 class W_MyType(W_MyObject):
     name = "foobar"
     flag_map_or_seq = '?'
+    hasuserdel = False
 
     def __init__(self):
         self.mro_w = [w_some_obj(), w_some_obj()]
         self.dict_w = {'__str__': w_some_obj()}
+        self.hasuserdel = True
 
     def get_module(self):
         return w_some_obj()
 
-
     def getname(self, space):
         return self.name.decode('utf-8')
 
diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py
--- a/pypy/objspace/std/bytesobject.py
+++ b/pypy/objspace/std/bytesobject.py
@@ -1,6 +1,6 @@
 """The builtin bytes implementation"""
 
-from rpython.rlib.jit import we_are_jitted
+from rpython.rlib import jit
 from rpython.rlib.objectmodel import (
     compute_hash, compute_unique_id, import_from_mixin, newlist_hint,
     resizelist_hint, HASH_ALGORITHM)
@@ -529,10 +529,22 @@
     @unwrap_spec(encoding='str_or_None', errors='str_or_None')
     def descr_new(space, w_stringtype, w_source=None, encoding=None,
                   errors=None):
-        if (w_source and space.is_w(space.type(w_source), space.w_bytes) and
-            space.is_w(w_stringtype, space.w_bytes) and encoding is None
-            and errors is None):
-            return w_source
+        if (w_source and space.is_w(w_stringtype, space.w_bytes)
+                and encoding is None and errors is None):
+            # special-case 'bytes(byte_object)'
+            w_srctype = space.type(w_source)
+            if w_srctype is space.w_bytes:
+                return w_source
+            # special-case 'bytes([single_integer])' or 'bytes((single_int,))'
+            # for JITted performance only, when we clearly see the
+            # length of the list/tuple being constant and equal to 1
+            if w_srctype is space.w_list or w_srctype is space.w_tuple:
+                length = space.len_w(w_source)
+                if jit.isconstant(length) and length == 1:
+                    w_item = space.getitem(w_source, space.wrap(0))
+                    value = getbytevalue(space, w_item)
+                    return W_BytesObject(value)
+        #
         value = newbytesdata_w(space, w_source, encoding, errors)
         w_obj = space.allocate_instance(W_BytesObject, w_stringtype)
         W_BytesObject.__init__(w_obj, value)
diff --git a/pypy/objspace/std/test/test_bytesobject.py b/pypy/objspace/std/test/test_bytesobject.py
--- a/pypy/objspace/std/test/test_bytesobject.py
+++ b/pypy/objspace/std/test/test_bytesobject.py
@@ -89,6 +89,13 @@
         assert self.space.listview_bytes(w_bytes) == None
         assert self.space.listview_int(w_bytes) == [97, 98, 99, 100]
 
+    def test_constructor_single_char(self, monkeypatch):
+        from rpython.rlib import jit
+        monkeypatch.setattr(jit, 'isconstant', lambda x: True)
+        space = self.space
+        w_res = space.call_function(space.w_bytes, space.wrap([42]))
+        assert space.str_w(w_res) == '*'
+
 class AppTestBytesObject:
 
     def test_constructor(self):
@@ -97,6 +104,23 @@
         assert bytes(b'abc') == b'abc'
         assert bytes('abc', 'ascii') == b'abc'
         assert bytes(set(b'foo')) in (b'fo', b'of')
+        assert bytes([]) == b''
+        assert bytes([42]) == b'*'
+        assert bytes([0xFC]) == b'\xFC'
+        assert bytes([42, 0xCC]) == b'*\xCC'
+
+    def test_constructor_list_of_objs(self):
+        class X:
+            def __index__(self):
+                return 42
+        class Y:
+            def __int__(self):
+                return 42
+        for obj in [42, X()]:
+            assert bytes([obj]) == b'*'
+            assert bytes([obj, obj, obj]) == b'***'
+        raises(TypeError, bytes, [Y()])
+        raises(TypeError, bytes, [Y(), Y()])
 
     def test_fromhex(self):
         assert bytes.fromhex("abcd") == b'\xab\xcd'
diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py
--- a/pypy/objspace/std/unicodeobject.py
+++ b/pypy/objspace/std/unicodeobject.py
@@ -1257,7 +1257,11 @@
 def unicode_to_decimal_w(space, w_unistr, allow_surrogates=False):
     if not isinstance(w_unistr, W_UnicodeObject):
         raise oefmt(space.w_TypeError, "expected unicode, got '%T'", w_unistr)
-    unistr = w_unistr._value
+    value = _rpy_unicode_to_decimal_w(space, w_unistr._value)
+    return unicodehelper.encode_utf8(space, value,
+                                     allow_surrogates=allow_surrogates)
+
+def _rpy_unicode_to_decimal_w(space, unistr):
     result = [u'\0'] * len(unistr)
     for i in xrange(len(unistr)):
         uchr = ord(unistr[i])
@@ -1270,8 +1274,7 @@
             except KeyError:
                 pass
         result[i] = unichr(uchr)
-    return unicodehelper.encode_utf8(space, u''.join(result),
-                                     allow_surrogates=allow_surrogates)
+    return u''.join(result)
 
 @jit.elidable
 def g_encode_utf8(value):
diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py
--- a/pypy/objspace/test/test_descroperation.py
+++ b/pypy/objspace/test/test_descroperation.py
@@ -280,7 +280,8 @@
             assert operate(A()) == "hello" * n
             assert type(operate(A())) is str
             answer = 42
-            raises(TypeError, operate, A())
+            excinfo = raises(TypeError, operate, A())
+            assert "returned non-string (type 'int')" in str(excinfo.value)
 
     def test_string_results_unicode(self):
         class A(object):
diff --git a/pypy/tool/pytest/apptest.py b/pypy/tool/pytest/apptest.py
--- a/pypy/tool/pytest/apptest.py
+++ b/pypy/tool/pytest/apptest.py
@@ -21,13 +21,6 @@
 
 pypyroot = os.path.dirname(pypydir)
 
-RENAMED_USEMODULES = dict(
-    _winreg='winreg',
-    exceptions='builtins',
-    struct='_struct',
-    thread='_thread',
-    operator='_operator',
-    )
 
 class AppError(Exception):
     def __init__(self, excinfo):
@@ -63,6 +56,11 @@
         return repr(value)
 
 
+def _rename_module(name):
+    mod = __import__("pypy.module." + name, globals(), locals(), ['Module'])
+    return mod.Module.applevel_name or name
+
+
 def run_with_python(python_, target_, usemodules, **definitions):
     if python_ is None:
         py.test.skip("Cannot find the default python3 interpreter to run with -A")
@@ -133,8 +131,7 @@
 
     check_usemodules = ''
     if usemodules:
-        usemodules = [str(RENAMED_USEMODULES.get(name, name))
-                      for name in usemodules]
+        usemodules = [_rename_module(name) for name in usemodules]
         check_usemodules = """\
     missing = set(%r).difference(sys.builtin_module_names)
     if missing:
diff --git a/pypy/tool/pytest/test/test_appsupport.py b/pypy/tool/pytest/test/test_appsupport.py
--- a/pypy/tool/pytest/test/test_appsupport.py
+++ b/pypy/tool/pytest/test/test_appsupport.py
@@ -135,3 +135,12 @@
     info = raises(ZeroDivisionError, "x/0")
     assert info.type is ZeroDivisionError
     assert isinstance(info.value, ZeroDivisionError)
+
+def test_rename_module():
+    from pypy.tool.pytest.apptest import _rename_module
+    assert _rename_module("sys") == "sys"
+    if sys.platform == "win32":
+        assert _rename_module("_winreg") == "winreg"
+    assert _rename_module("struct") == "_struct"
+    assert _rename_module("operator") == "_operator"
+    assert _rename_module("signal") == "_signal"
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
@@ -155,7 +155,10 @@
 # 'old_objects_pointing_to_pinned' and doesn't have to be added again.
 GCFLAG_PINNED_OBJECT_PARENT_KNOWN = GCFLAG_PINNED
 
-_GCFLAG_FIRST_UNUSED = first_gcflag << 10    # the first unused bit
+# record that ignore_finalizer() has been called
+GCFLAG_IGNORE_FINALIZER = first_gcflag << 10
+
+_GCFLAG_FIRST_UNUSED = first_gcflag << 11    # the first unused bit
 
 
 # States for the incremental GC
@@ -1161,6 +1164,11 @@
             obj = self.get_forwarding_address(obj)
         return self.get_type_id(obj)
 
+    def get_possibly_forwarded_tid(self, obj):
+        if self.is_in_nursery(obj) and self.is_forwarded(obj):
+            obj = self.get_forwarding_address(obj)
+        return self.header(obj).tid
+
     def get_total_memory_used(self):
         """Return the total memory used, not counting any object in the
         nursery: only objects in the ArenaCollection or raw-malloced.
@@ -1672,7 +1680,7 @@
             self.rrc_minor_collection_trace()
         #
         # visit the "probably young" objects with finalizers.  They
-        # always all survive.
+        # all survive, except if IGNORE_FINALIZER is set.
         if self.probably_young_objects_with_finalizers.non_empty():
             self.deal_with_young_objects_with_finalizers()
         #
@@ -2675,6 +2683,8 @@
         while self.probably_young_objects_with_finalizers.non_empty():
             obj = self.probably_young_objects_with_finalizers.popleft()
             fq_nr = self.probably_young_objects_with_finalizers.popleft()
+            if self.get_possibly_forwarded_tid(obj) & GCFLAG_IGNORE_FINALIZER:
+                continue
             self.singleaddr.address[0] = obj
             self._trace_drag_out1(self.singleaddr)
             obj = self.singleaddr.address[0]
@@ -2697,6 +2707,8 @@
             fq_nr = self.old_objects_with_finalizers.popleft()
             ll_assert(self._finalization_state(x) != 1,
                       "bad finalization state 1")
+            if self.header(x).tid & GCFLAG_IGNORE_FINALIZER:
+                continue
             if self.header(x).tid & GCFLAG_VISITED:
                 new_with_finalizer.append(x)
                 new_with_finalizer.append(fq_nr)
@@ -2787,6 +2799,9 @@
         self.objects_to_trace.append(obj)
         self.visit_all_objects()
 
+    def ignore_finalizer(self, obj):
+        self.header(obj).tid |= GCFLAG_IGNORE_FINALIZER
+
 
     # ----------
     # Weakrefs
diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -545,6 +545,12 @@
                                              s_gcref],
                                             annmodel.s_None)
 
+        self.ignore_finalizer_ptr = None
+        if hasattr(GCClass, 'ignore_finalizer'):
+            self.ignore_finalizer_ptr = getfn(GCClass.ignore_finalizer,
+                                              [s_gc, SomeAddress()],
+                                              annmodel.s_None)
+
     def create_custom_trace_funcs(self, gc, rtyper):
         custom_trace_funcs = tuple(rtyper.custom_trace_funcs)
         rtyper.custom_trace_funcs = custom_trace_funcs
@@ -1572,6 +1578,13 @@
         hop.genop("cast_adr_to_ptr", [v_adr],
                   resultvar = hop.spaceop.result)
 
+    def gct_gc_ignore_finalizer(self, hop):
+        if self.ignore_finalizer_ptr is not None:
+            v_adr = hop.genop("cast_ptr_to_adr", [hop.spaceop.args[0]],
+                              resulttype=llmemory.Address)
+            hop.genop("direct_call", [self.ignore_finalizer_ptr,
+                                      self.c_const_gc, v_adr])
+
 
 class TransformerLayoutBuilder(gctypelayout.TypeLayoutBuilder):
 
diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -4,7 +4,7 @@
 """
 
 import os, stat, errno, sys
-from rpython.rlib import rposix
+from rpython.rlib import rposix, rgc
 from rpython.rlib.objectmodel import enforceargs
 from rpython.rlib.rarithmetic import intmask
 from rpython.rlib.rstring import StringBuilder
@@ -294,6 +294,7 @@
         if ll_file:
             # double close is allowed
             self._ll_file = lltype.nullptr(FILEP.TO)
+            rgc.may_ignore_finalizer(self)
             do_close = self._close2[0]
             try:
                 if do_close:
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -527,6 +527,14 @@
         hop.exception_cannot_occur()
         return hop.inputconst(lltype.Signed, hop.s_result.const)
 
+ at jit.dont_look_inside
+ at specialize.argtype(0)
+def may_ignore_finalizer(obj):
+    """Optimization hint: says that it is valid for any finalizer
+    for 'obj' to be ignored, depending on the GC."""
+    from rpython.rtyper.lltypesystem.lloperation import llop
+    llop.gc_ignore_finalizer(lltype.Void, obj)
+
 
 # ____________________________________________________________
 
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -486,6 +486,7 @@
     'gc_add_memory_pressure': LLOp(),
     'gc_fq_next_dead'     : LLOp(),
     'gc_fq_register'      : LLOp(),
+    'gc_ignore_finalizer' : LLOp(canrun=True),
 
     'gc_rawrefcount_init':              LLOp(),
     'gc_rawrefcount_create_link_pypy':  LLOp(),
diff --git a/rpython/rtyper/lltypesystem/opimpl.py b/rpython/rtyper/lltypesystem/opimpl.py
--- a/rpython/rtyper/lltypesystem/opimpl.py
+++ b/rpython/rtyper/lltypesystem/opimpl.py
@@ -736,6 +736,9 @@
     assert isinstance(x, bool)
     return x
 
+def op_gc_ignore_finalizer(obj):
+    pass
+
 # ____________________________________________________________
 
 def get_op_impl(opname):
diff --git a/rpython/translator/c/src/mem.h b/rpython/translator/c/src/mem.h
--- a/rpython/translator/c/src/mem.h
+++ b/rpython/translator/c/src/mem.h
@@ -152,6 +152,7 @@
 #define OP_GC_IS_RPY_INSTANCE(x, r)      r = 0
 #define OP_GC_DUMP_RPY_HEAP(fd, r)       r = 0
 #define OP_GC_SET_EXTRA_THRESHOLD(x, r)  /* nothing */
+#define OP_GC_IGNORE_FINALIZER(x, r)     /* nothing */
 
 /****************************/
 /* The "asmgcc" root finder */
diff --git a/rpython/translator/c/test/test_boehm.py b/rpython/translator/c/test/test_boehm.py
--- a/rpython/translator/c/test/test_boehm.py
+++ b/rpython/translator/c/test/test_boehm.py
@@ -409,7 +409,9 @@
         #
         def fn():
             for i in range(1000):
-                fq.register_finalizer(A(i))
+                x = A(i)
+                fq.register_finalizer(x)
+                rgc.may_ignore_finalizer(x)   # this is ignored with Boehm
             rgc.collect()
             rgc.collect()
             if glob.triggered == 0:
diff --git a/rpython/translator/c/test/test_newgc.py b/rpython/translator/c/test/test_newgc.py
--- a/rpython/translator/c/test/test_newgc.py
+++ b/rpython/translator/c/test/test_newgc.py
@@ -1705,6 +1705,38 @@
             res = self.run("limited_memory_linux", -1, runner=myrunner)
             assert res == 42
 
+    def define_ignore_finalizer(cls):
+        class X(object):
+            pass
+        class FQ(rgc.FinalizerQueue):
+            Class = X
+            def finalizer_trigger(self):
+                pass
+        queue = FQ()
+        def g():
+            x1 = X()
+            x2 = X()
+            queue.register_finalizer(x1)
+            queue.register_finalizer(x2)
+            rgc.may_ignore_finalizer(x1)
+        g._dont_inline_ = True
+        def f():
+            g()
+            rgc.collect()
+            seen = 0
+            while True:
+                obj = queue.next_dead()
+                if obj is None:
+                    break
+                seen += 1
+            return seen
+        assert f() == 2    # untranslated: may_ignore_finalizer() is ignored
+        return f
+
+    def test_ignore_finalizer(self):
+        res = self.run("ignore_finalizer")
+        assert res == 1    # translated: x1 is removed from the list
+
 
 # ____________________________________________________________________
 


More information about the pypy-commit mailing list