Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: PyBuffer
Changeset: r91094:165dc3ba1754
Date: 2017-04-19 17:05 +0100
http://bitbucket.org/pypy/pypy/changeset/165dc3ba1754/

Log:    hg merge py3.5

diff too long, truncating to 2000 out of 20552 lines

diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -53,9 +53,11 @@
 ^rpython/translator/goal/.+\.dll$
 ^pypy/goal/pypy-translation-snapshot$
 ^pypy/goal/pypy-c
+^pypy/goal/pypy3-c
 ^pypy/goal/.+\.exe$
 ^pypy/goal/.+\.dll$
 ^pypy/goal/.+\.lib$
+^pypy/goal/.+\.dylib$
 ^pypy/_cache$
 ^lib-python/2.7/lib2to3/.+\.pickle$
 ^lib_pypy/__pycache__$
@@ -86,3 +88,5 @@
 ^\.cache$
 
 pypy/module/cppyy/.+/*\.pcm
+
+
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -36,3 +36,5 @@
 aff251e543859ce4508159dd9f1a82a2f553de00 release-pypy2.7-v5.6.0
 fa3249d55d15b9829e1be69cdf45b5a44cec902d release-pypy2.7-v5.7.0
 b16a4363e930f6401bceb499b9520955504c6cb0 release-pypy3.5-v5.7.0
+1aa2d8e03cdfab54b7121e93fda7e98ea88a30bf release-pypy2.7-v5.7.1
+2875f328eae2216a87f3d6f335092832eb031f56 release-pypy3.5-v5.7.1
diff --git a/lib-python/2.7/distutils/sysconfig_pypy.py 
b/lib-python/2.7/distutils/sysconfig_pypy.py
--- a/lib-python/2.7/distutils/sysconfig_pypy.py
+++ b/lib-python/2.7/distutils/sysconfig_pypy.py
@@ -61,12 +61,12 @@
 def _init_posix():
     """Initialize the module as appropriate for POSIX systems."""
     g = {}
-    g['CC'] = "gcc -pthread"
-    g['CXX'] = "g++ -pthread"
+    g['CC'] = "cc -pthread"
+    g['CXX'] = "c++ -pthread"
     g['OPT'] = "-DNDEBUG -O2"
     g['CFLAGS'] = "-DNDEBUG -O2"
     g['CCSHARED'] = "-fPIC"
-    g['LDSHARED'] = "gcc -pthread -shared"
+    g['LDSHARED'] = "cc -pthread -shared"
     g['SO'] = [s[0] for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION][0]
     g['AR'] = "ar"
     g['ARFLAGS'] = "rc"
diff --git a/lib-python/3/site.py b/lib-python/3/site.py
--- a/lib-python/3/site.py
+++ b/lib-python/3/site.py
@@ -305,9 +305,7 @@
         seen.add(prefix)
 
         if is_pypy:
-            from distutils.sysconfig import get_python_lib
-            sitepackages.append(get_python_lib(standard_lib=False,
-                                               prefix=prefix))
+            sitepackages.append(os.path.join(prefix, "site-packages"))
         elif os.sep == '/':
             sitepackages.append(os.path.join(prefix, "lib",
                                         "python" + sys.version[:3],
diff --git a/lib_pypy/_cffi_ssl/README.md b/lib_pypy/_cffi_ssl/README.md
--- a/lib_pypy/_cffi_ssl/README.md
+++ b/lib_pypy/_cffi_ssl/README.md
@@ -5,16 +5,22 @@
 it renames the compiled shared object to _pypy_openssl.so (which means
 that cryptography can ship their own cffi backend)
 
+NOTE: currently, we have changed ``_cffi_src/openssl/callbacks.py`` to
+not rely on the CPython C API.
+
 # Tests?
 
 Currently this module is tested using CPython's standard library test suite.
 
 # Install it into PyPy's source tree
 
-Copy over all the sources into the folder `lib_pypy/_cffi_ssl/*`. Updating the 
cffi backend can be simply done by the following command:
+Copy over all the sources into the folder `lib_pypy/_cffi_ssl/*`. Updating the 
cffi backend can be simply done by the following command::
 
     $ cp -r <cloned cryptography folder>/src/_cffi_src/* .
 
+NOTE: you need to keep our version of ``_cffi_src/openssl/callbacks.py``
+for now!
+
 # Crpytography version
 
 Copied over release version `1.7.2`
diff --git a/lib_pypy/_cffi_ssl/_cffi_src/openssl/callbacks.py 
b/lib_pypy/_cffi_ssl/_cffi_src/openssl/callbacks.py
--- a/lib_pypy/_cffi_ssl/_cffi_src/openssl/callbacks.py
+++ b/lib_pypy/_cffi_ssl/_cffi_src/openssl/callbacks.py
@@ -13,8 +13,6 @@
 #include <openssl/x509.h>
 #include <openssl/x509_vfy.h>
 #include <openssl/crypto.h>
-
-#include <pythread.h>
 """
 
 TYPES = """
@@ -64,8 +62,44 @@
    Copyright 2001-2016 Python Software Foundation; All Rights Reserved.
 */
 
+#ifdef _WIN32
+#include <Windows.h>
+typedef CRITICAL_SECTION mutex1_t;
+static inline void mutex1_init(mutex1_t *mutex) {
+    InitializeCriticalSection(mutex);
+}
+static inline void mutex1_lock(mutex1_t *mutex) {
+    EnterCriticalSection(mutex);
+}
+static inline void mutex1_unlock(mutex1_t *mutex) {
+    LeaveCriticalSection(mutex);
+}
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+typedef pthread_mutex_t mutex1_t;
+#define ASSERT_STATUS(call)                             \
+    if (call != 0) {                                    \
+        perror("Fatal error in _cffi_ssl: " #call);     \
+        abort();                                        \
+    }
+static inline void mutex1_init(mutex1_t *mutex) {
+#if !defined(pthread_mutexattr_default)
+#  define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL)
+#endif
+    ASSERT_STATUS(pthread_mutex_init(mutex, pthread_mutexattr_default));
+}
+static inline void mutex1_lock(mutex1_t *mutex) {
+    ASSERT_STATUS(pthread_mutex_lock(mutex));
+}
+static inline void mutex1_unlock(mutex1_t *mutex) {
+    ASSERT_STATUS(pthread_mutex_unlock(mutex));
+}
+#endif
+
 static unsigned int _ssl_locks_count = 0;
-static PyThread_type_lock *_ssl_locks = NULL;
+static mutex1_t *_ssl_locks = NULL;
 
 static void _ssl_thread_locking_function(int mode, int n, const char *file,
                                          int line) {
@@ -89,35 +123,32 @@
     }
 
     if (mode & CRYPTO_LOCK) {
-        PyThread_acquire_lock(_ssl_locks[n], 1);
+        mutex1_lock(_ssl_locks + n);
     } else {
-        PyThread_release_lock(_ssl_locks[n]);
+        mutex1_unlock(_ssl_locks + n);
+    }
+}
+
+static void init_mutexes(void)
+{
+    int i;
+    for (i = 0;  i < _ssl_locks_count;  i++) {
+        mutex1_init(_ssl_locks + i);
     }
 }
 
 int _setup_ssl_threads(void) {
-    unsigned int i;
-
     if (_ssl_locks == NULL) {
         _ssl_locks_count = CRYPTO_num_locks();
-        _ssl_locks = PyMem_New(PyThread_type_lock, _ssl_locks_count);
+        _ssl_locks = malloc(sizeof(mutex1_t) * _ssl_locks_count);
         if (_ssl_locks == NULL) {
-            PyErr_NoMemory();
             return 0;
         }
-        memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count);
-        for (i = 0;  i < _ssl_locks_count;  i++) {
-            _ssl_locks[i] = PyThread_allocate_lock();
-            if (_ssl_locks[i] == NULL) {
-                unsigned int j;
-                for (j = 0;  j < i;  j++) {
-                    PyThread_free_lock(_ssl_locks[j]);
-                }
-                PyMem_Free(_ssl_locks);
-                return 0;
-            }
-        }
+        init_mutexes();
         CRYPTO_set_locking_callback(_ssl_thread_locking_function);
+#ifndef _WIN32
+        pthread_atfork(NULL, NULL, &init_mutexes);
+#endif
     }
     return 1;
 }
diff --git a/lib_pypy/_ctypes/array.py b/lib_pypy/_ctypes/array.py
--- a/lib_pypy/_ctypes/array.py
+++ b/lib_pypy/_ctypes/array.py
@@ -83,8 +83,9 @@
         res = self.__new__(self)
         ffiarray = self._ffiarray.fromaddress(resarray.buffer, self._length_)
         res._buffer = ffiarray
-        res._base = base
-        res._index = index
+        if base is not None:
+            res._base = base
+            res._index = index
         return res
 
     def _CData_retval(self, resbuffer):
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -64,8 +64,9 @@
         res = object.__new__(self)
         res.__class__ = self
         res.__dict__['_buffer'] = resbuffer
-        res.__dict__['_base'] = base
-        res.__dict__['_index'] = index
+        if base is not None:
+            res.__dict__['_base'] = base
+            res.__dict__['_index'] = index
         return res
 
     def _CData_retval(self, resbuffer):
diff --git a/lib_pypy/_pypy_collections.py b/lib_pypy/_pypy_collections.py
--- a/lib_pypy/_pypy_collections.py
+++ b/lib_pypy/_pypy_collections.py
@@ -1,6 +1,5 @@
-from __pypy__ import reversed_dict, move_to_end
+from __pypy__ import reversed_dict, move_to_end, objects_in_repr
 from _operator import eq as _eq
-from reprlib import recursive_repr as _recursive_repr
 import _collections_abc
 
 
@@ -44,12 +43,21 @@
         '''
         return move_to_end(self, key, last)
 
-    @_recursive_repr()
     def __repr__(self):
         'od.__repr__() <==> repr(od)'
         if not self:
             return '%s()' % (self.__class__.__name__,)
-        return '%s(%r)' % (self.__class__.__name__, list(self.items()))
+        currently_in_repr = objects_in_repr()
+        if self in currently_in_repr:
+            return '...'
+        currently_in_repr[self] = 1
+        try:
+            return '%s(%r)' % (self.__class__.__name__, list(self.items()))
+        finally:
+            try:
+                del currently_in_repr[self]
+            except:
+                pass
 
     def __reduce__(self):
         'Return state information for pickling'
diff --git a/lib_pypy/_structseq.py b/lib_pypy/_structseq.py
--- a/lib_pypy/_structseq.py
+++ b/lib_pypy/_structseq.py
@@ -129,3 +129,38 @@
     parts = ["%s=%r" % (fields[index].__name__, value)
             for index, value in enumerate(self[:visible_count])]
     return "%s(%s)" % (self._name, ", ".join(parts))
+
+
+class SimpleNamespace:
+    """A simple attribute-based namespace.
+
+SimpleNamespace(**kwargs)"""
+
+    def __init__(self, **kwargs):
+        self.__dict__.update(kwargs)
+
+    def __repr__(self):
+        ident = id(self)
+        if ident in sns_recurse:
+            return "namespace(...)"
+        sns_recurse.add(ident)
+        try:
+            pairs = ('%s=%r' % item for item in sorted(self.__dict__.items()))
+            return "namespace(%s)" % ', '.join(pairs)
+        finally:
+            sns_recurse.discard(ident)
+
+    def __eq__(self, other):
+        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/lib_pypy/_sysconfigdata.py b/lib_pypy/_sysconfigdata.py
--- a/lib_pypy/_sysconfigdata.py
+++ b/lib_pypy/_sysconfigdata.py
@@ -1,6 +1,6 @@
-import imp
+import _imp
 
-so_ext = [s[0] for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION][0]
+so_ext = _imp.extension_suffixes()[0]
 
 build_time_vars = {
     "EXT_SUFFIX": so_ext,
diff --git a/pypy/doc/index-of-release-notes.rst 
b/pypy/doc/index-of-release-notes.rst
--- a/pypy/doc/index-of-release-notes.rst
+++ b/pypy/doc/index-of-release-notes.rst
@@ -6,6 +6,7 @@
 
 .. toctree::
 
+   release-v5.7.1.rst
    release-v5.7.0.rst
    release-pypy2.7-v5.6.0.rst
    release-pypy2.7-v5.4.1.rst
@@ -59,6 +60,7 @@
 
 .. toctree::
 
+   release-v5.7.1.rst
    release-v5.7.0.rst
 
 CPython 3.3 compatible versions
diff --git a/pypy/doc/install.rst b/pypy/doc/install.rst
--- a/pypy/doc/install.rst
+++ b/pypy/doc/install.rst
@@ -32,10 +32,10 @@
 
 .. code-block:: console
 
-    $ tar xf pypy-2.1.tar.bz2
-    $ ./pypy-2.1/bin/pypy
-    Python 2.7.3 (480845e6b1dd, Jul 31 2013, 11:05:31)
-    [PyPy 2.1.0 with GCC 4.4.3] on linux2
+    $ tar xf pypy-x.y.z.tar.bz2
+    $ ./pypy-x.y.z/bin/pypy
+    Python 2.7.x (xxxxxxxxxxxx, Date, Time)
+    [PyPy x.y.z with GCC x.y.z] on linux2
     Type "help", "copyright", "credits" or "license" for more information.
     And now for something completely different: ``PyPy is an exciting 
technology
     that lets you to write fast, portable, multi-platform interpreters with 
less
diff --git a/pypy/doc/release-v5.7.0.rst b/pypy/doc/release-v5.7.0.rst
--- a/pypy/doc/release-v5.7.0.rst
+++ b/pypy/doc/release-v5.7.0.rst
@@ -99,7 +99,7 @@
     tp_dealloc
   * refactor and clean up poor handling of unicode exposed in work on py3.5
   * builtin module cppyy_ supports C++ 11, 14, etc. via cling (reflex has been 
removed)
-  * adapt ``weakref`` according to CPython issue #19542_, will be in CPython 
2.7.14
+  * adapt ``weakref`` according to CPython issue 19542_, will be in CPython 
2.7.14
   * support translations with cpyext and the Boehm GC (for special cases like
     RevDB_
   * implement ``StringBuffer.get_raw_address`` for the buffer protocol, it is
@@ -125,18 +125,18 @@
   * disable ``clock_gettime()`` on OS/X, since we support 10.11 and it was only
     added in 10.12
   * support ``HAVE_FSTATVFS`` which was unintentionally always false
-  * fix user-created C-API heaptype, issue #2434_
+  * fix user-created C-API heaptype, issue 2434_
   * fix ``PyDict_Update`` is not actually the same as ``dict.update``
   * assign ``tp_doc`` on ``PyTypeObject`` and tie it to the app-level 
``__doc__`` attribute
-    issue #2446_
+    issue 2446_
   * clean up memory leaks around ``PyObject_GetBuffer``, 
``PyMemoryView_GET_BUFFER``,
     ``PyMemoryView_FromBuffer``, and ``PyBuffer_Release``
   * improve support for creating C-extension objects from app-level classes,
     filling more slots, especially ``tp_new`` and ``tp_dealloc``
-  * fix for ``ctypes.c_bool`` returning ``bool`` restype, issue #2475_
+  * fix for ``ctypes.c_bool`` returning ``bool`` restype, issue 2475_
   * fix in corner cases with the GIL and C-API functions
-  * allow overriding thread.local.__init__ in a subclass, issue #2501_
-  * allow ``PyClass_New`` to be called with NULL as the first arguemnt, issue 
#2504_
+  * allow overriding thread.local.__init__ in a subclass, issue 2501_
+  * allow ``PyClass_New`` to be called with NULL as the first arguemnt, issue 
2504_
 
 
 * Performance improvements:
diff --git a/pypy/doc/release-v5.7.1.rst b/pypy/doc/release-v5.7.1.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-v5.7.1.rst
@@ -0,0 +1,50 @@
+==========
+PyPy 5.7.1
+==========
+
+We have released a bugfix PyPy2.7-v5.7.1 and PyPy3.5-v5.7.1 beta (Linux 64bit),
+due to the following issues:
+
+  * correctly handle an edge case in dict.pop (issue 2508_)
+
+  * fix a regression to correctly handle multiple inheritance in a C-API type
+    where the second base is an app-level class with a ``__new__`` function
+
+  * fix a regression to fill a C-API type's ``tp_getattr`` slot from a
+    ``__getattr__`` method (issue 2523_)
+
+Thanks to those who reported the issues.
+
+.. _2508: https://bitbucket.org/pypy/pypy/issues/2508
+.. _2523: https://bitbucket.org/pypy/pypy/issues/2523
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7 and CPython 3.5. It's fast (`PyPy and CPython 2.7.x`_ performance 
comparison)
+due to its integrated tracing JIT compiler.
+
+We also welcome developers of other `dynamic languages`_ to see what RPython
+can do for them.
+
+The PyPy 2.7 release supports: 
+
+  * **x86** machines on most common operating systems
+    (Linux 32/64 bits, Mac OS X 64 bits, Windows 32 bits, OpenBSD, FreeBSD)
+  
+  * newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux,
+  
+  * big- and little-endian variants of **PPC64** running Linux,
+
+  * **s390x** running Linux
+
+.. _`PyPy and CPython 2.7.x`: http://speed.pypy.org
+.. _`dynamic languages`: http://rpython.readthedocs.io/en/latest/examples.html
+
+Please update, and continue to help us make PyPy better.
+
+Cheers
+
+The PyPy Team
+
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
@@ -21,3 +21,10 @@
 .. branch: vmprof-native
 
 PyPy support to profile native frames in vmprof.
+
+.. branch: reusing-r11
+.. branch: branch-prediction
+
+Performance tweaks in the x86 JIT-generated machine code: rarely taken
+blocks are moved off-line.  Also, the temporary register used to contain
+large constants is reused across instructions.
diff --git a/pypy/doc/whatsnew-pypy3-head.rst b/pypy/doc/whatsnew-pypy3-head.rst
--- a/pypy/doc/whatsnew-pypy3-head.rst
+++ b/pypy/doc/whatsnew-pypy3-head.rst
@@ -18,3 +18,6 @@
 
 Implement posix.posix_fallocate() and posix.posix_fadvise()
 
+.. branch: py3.5-mac-translate
+
+Fix for different posix primitives on MacOS
diff --git a/pypy/interpreter/astcompiler/assemble.py 
b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -7,6 +7,7 @@
 from pypy.interpreter.astcompiler import ast, consts, misc, symtable
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.pycode import PyCode
+from pypy.interpreter.miscutils import string_sort
 from pypy.tool import stdlib_opcode as ops
 
 
@@ -138,9 +139,12 @@
 
 
 def _make_index_dict_filter(syms, flag1, flag2):
+    names = syms.keys()
+    string_sort(names)   # return cell vars in alphabetical order
     i = 0
     result = {}
-    for name, scope in syms.iteritems():
+    for name in names:
+        scope = syms[name]
         if scope in (flag1, flag2):
             result[name] = i
             i += 1
@@ -172,6 +176,7 @@
         self.cell_vars = _make_index_dict_filter(scope.symbols,
                                                  symtable.SCOPE_CELL,
                                                  symtable.SCOPE_CELL_CLASS)
+        string_sort(scope.free_vars)    # return free vars in alphabetical 
order
         self.free_vars = _iter_to_dict(scope.free_vars, len(self.cell_vars))
         self.w_consts = space.newdict()
         self.argcount = 0
diff --git a/pypy/interpreter/astcompiler/symtable.py 
b/pypy/interpreter/astcompiler/symtable.py
--- a/pypy/interpreter/astcompiler/symtable.py
+++ b/pypy/interpreter/astcompiler/symtable.py
@@ -38,7 +38,7 @@
         self.roles = {}
         self.varnames = []
         self.children = []
-        self.free_vars = {}
+        self.free_vars = []    # a bag of names: the order doesn't matter here
         self.temp_name_counter = 1
         self.has_free = False
         self.child_has_free = False
@@ -135,7 +135,8 @@
                 err = "no binding for nonlocal '%s' found" % (name,)
                 raise SyntaxError(err, self.lineno, self.col_offset)
             self.symbols[name] = SCOPE_FREE
-            self.free_vars[name] = None
+            if not self._hide_bound_from_nested_scopes:
+                self.free_vars.append(name)
             free[name] = None
             self.has_free = True
         elif flags & SYM_BOUND:
@@ -147,7 +148,7 @@
                 pass
         elif bound and name in bound:
             self.symbols[name] = SCOPE_FREE
-            self.free_vars[name] = None
+            self.free_vars.append(name)
             free[name] = None
             self.has_free = True
         elif name in globs:
@@ -204,7 +205,7 @@
             except KeyError:
                 if bound and name in bound:
                     self.symbols[name] = SCOPE_FREE
-                    self.free_vars[name] = None
+                    self.free_vars.append(name)
             else:
                 if role_here & (SYM_BOUND | SYM_GLOBAL) and \
                         self._hide_bound_from_nested_scopes:
@@ -213,7 +214,7 @@
                     # scope.  We add the name to the class scope's list of free
                     # vars, so it will be passed through by the interpreter, 
but
                     # we leave the scope alone, so it can be local on its own.
-                    self.free_vars[name] = None
+                    self.free_vars.append(name)
         self._check_optimization()
         free.update(new_free)
 
diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py
--- a/pypy/interpreter/miscutils.py
+++ b/pypy/interpreter/miscutils.py
@@ -2,6 +2,9 @@
 Miscellaneous utilities.
 """
 
+from rpython.rlib.listsort import make_timsort_class
+
+
 class ThreadLocals:
     """Pseudo thread-local storage, for 'space.threadlocals'.
     This is not really thread-local at all; the intention is that the PyPy
@@ -53,3 +56,15 @@
             def set(self, key, value):
                 self._dict[key] = value
         return FakeWeakValueDict()
+
+
+_StringBaseTimSort = make_timsort_class()
+
+class StringSort(_StringBaseTimSort):
+    def lt(self, a, b):
+        return a < b
+
+def string_sort(lst):
+    """Sort a (resizable) list of strings."""
+    sorter = StringSort(lst, len(lst))
+    sorter.sort()
diff --git a/pypy/interpreter/test/test_compiler.py 
b/pypy/interpreter/test/test_compiler.py
--- a/pypy/interpreter/test/test_compiler.py
+++ b/pypy/interpreter/test/test_compiler.py
@@ -1035,6 +1035,32 @@
         else:
             assert l1 == l2 == l3 == l4 == [1, 3, 2, 4]
 
+    def test_freevars_order(self):
+        # co_cellvars and co_freevars are guaranteed to appear in
+        # alphabetical order.  See CPython Issue #15368 (which does
+        # not come with tests).
+        source = """if 1:
+        def f1(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15):
+            def g1():
+                return (x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15)
+            return g1
+        def f2(x15,x14,x13,x12,x11,x10,x9,x8,x7,x6,x5,x4,x3,x2,x1):
+            def g2():
+                return (x15,x14,x13,x12,x11,x10,x9,x8,x7,x6,x5,x4,x3,x2,x1)
+            return g2
+        c1 = f1(*range(15)).__code__.co_freevars
+        c2 = f2(*range(15)).__code__.co_freevars
+        r1 = f1.__code__.co_cellvars
+        r2 = f2.__code__.co_cellvars
+        """
+        d = {}
+        exec(source, d)
+        assert d['c1'] == d['c2']
+        # the test above is important for a few bytecode hacks,
+        # but actually we get them in alphabetical order, so check that:
+        assert d['c1'] == tuple(sorted(d['c1']))
+        assert d['r1'] == d['r2'] == d['c1']
+
     def test_ast_equality(self):
         import _ast
         sample_code = [
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -67,6 +67,7 @@
     interpleveldefs = {
         'attach_gdb'                : 'interp_magic.attach_gdb',
         'internal_repr'             : 'interp_magic.internal_repr',
+        'objects_in_repr'           : 'interp_magic.objects_in_repr',
         'bytebuffer'                : 'bytebuffer.bytebuffer',
         'identity_dict'             : 'interp_identitydict.W_IdentityDict',
         'debug_start'               : 'interp_debug.debug_start',
diff --git a/pypy/module/__pypy__/interp_magic.py 
b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -15,6 +15,14 @@
 def internal_repr(space, w_object):
     return space.newtext('%r' % (w_object,))
 
+def objects_in_repr(space):
+    """The identitydict of objects currently being repr().
+
+    This object is thread-local and can be used in a __repr__ method
+    to avoid recursion.
+    """
+    return space.get_objects_in_repr()
+
 
 def attach_gdb(space):
     """Run an interp-level gdb (or pdb when untranslated)"""
diff --git a/pypy/module/_collections/interp_deque.py 
b/pypy/module/_collections/interp_deque.py
--- a/pypy/module/_collections/interp_deque.py
+++ b/pypy/module/_collections/interp_deque.py
@@ -406,11 +406,7 @@
 
     def repr(self):
         space = self.space
-        ec = space.getexecutioncontext()
-        w_currently_in_repr = ec._py_repr
-        if w_currently_in_repr is None:
-            w_currently_in_repr = ec._py_repr = space.newdict()
-        return dequerepr(space, w_currently_in_repr, self)
+        return dequerepr(space, space.get_objects_in_repr(), self)
 
     @specialize.arg(2)
     def compare(self, w_other, op):
@@ -523,18 +519,17 @@
 app = gateway.applevel("""
     def dequerepr(currently_in_repr, d):
         'The app-level part of repr().'
-        deque_id = id(d)
-        if deque_id in currently_in_repr:
+        if d in currently_in_repr:
             return '[...]'   # strange because it's a deque and this
                              # strongly suggests it's a list instead,
                              # but confirmed behavior from python-dev
         else:
-            currently_in_repr[deque_id] = 1
+            currently_in_repr[d] = 1
             try:
                 listrepr = "[" + ", ".join([repr(x) for x in d]) + ']'
             finally:
                 try:
-                    del currently_in_repr[deque_id]
+                    del currently_in_repr[d]
                 except:
                     pass
         if d.maxlen is None:
diff --git a/pypy/module/_collections/test/test_ordereddict.py 
b/pypy/module/_collections/test/test_ordereddict.py
--- a/pypy/module/_collections/test/test_ordereddict.py
+++ b/pypy/module/_collections/test/test_ordereddict.py
@@ -6,3 +6,9 @@
         from _collections import OrderedDict
         assert issubclass(OrderedDict, dict)
         assert hasattr(OrderedDict, 'move_to_end')
+
+    def test_recursive_repr(self):
+        from _collections import OrderedDict
+        d = OrderedDict()
+        d[1] = d
+        assert repr(d) == 'OrderedDict([(1, ...)])'
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
@@ -1035,7 +1035,12 @@
             raise oefmt(space.w_ValueError,
                         "I/O operation on uninitialized object")
         w_meth = space.getattr(self.w_reader, space.newtext("close"))
-        space.call_args(w_meth, __args__)
+        try:
+            space.call_args(w_meth, __args__)
+        except OperationError as e2:
+            if e:
+                e2.chain_exceptions(space, e)
+            e = e2
 
         if e:
             raise e
diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py
--- a/pypy/module/_io/interp_io.py
+++ b/pypy/module/_io/interp_io.py
@@ -86,46 +86,61 @@
     if binary and newline is not None:
         raise oefmt(space.w_ValueError,
                     "binary mode doesn't take a newline argument")
-    w_raw = space.call_function(
-        space.gettypefor(W_FileIO), w_file, space.newtext(rawmode),
-        space.newbool(bool(closefd)), w_opener)
 
-    isatty = space.is_true(space.call_method(w_raw, "isatty"))
-    line_buffering = buffering == 1 or (buffering < 0 and isatty)
-    if line_buffering:
-        buffering = -1
+    w_result = None
+    try:
+        w_raw = space.call_function(
+            space.gettypefor(W_FileIO), w_file, space.newtext(rawmode),
+            space.newbool(bool(closefd)), w_opener)
+        w_result = w_raw
 
-    if buffering < 0:
-        buffering = space.c_int_w(space.getattr(w_raw, 
space.newtext("_blksize")))
+        isatty = space.is_true(space.call_method(w_raw, "isatty"))
+        line_buffering = buffering == 1 or (buffering < 0 and isatty)
+        if line_buffering:
+            buffering = -1
 
-    if buffering < 0:
-        raise oefmt(space.w_ValueError, "invalid buffering size")
+        if buffering < 0:
+            buffering = space.c_int_w(space.getattr(
+                w_raw, space.newtext("_blksize")))
 
-    if buffering == 0:
-        if not binary:
-            raise oefmt(space.w_ValueError, "can't have unbuffered text I/O")
-        return w_raw
+        if buffering < 0:
+            raise oefmt(space.w_ValueError, "invalid buffering size")
 
-    if updating:
-        buffer_cls = W_BufferedRandom
-    elif writing or creating or appending:
-        buffer_cls = W_BufferedWriter
-    elif reading:
-        buffer_cls = W_BufferedReader
-    else:
-        raise oefmt(space.w_ValueError, "unknown mode: '%s'", mode)
-    w_buffer = space.call_function(
-        space.gettypefor(buffer_cls), w_raw, space.newint(buffering)
-    )
-    if binary:
-        return w_buffer
+        if buffering == 0:
+            if not binary:
+                raise oefmt(space.w_ValueError,
+                            "can't have unbuffered text I/O")
+            return w_result
 
-    w_wrapper = space.call_function(space.gettypefor(W_TextIOWrapper),
-        w_buffer,
-        space.newtext_or_none(encoding),
-        space.newtext_or_none(errors),
-        space.newtext_or_none(newline),
-        space.newbool(line_buffering)
-    )
-    space.setattr(w_wrapper, space.newtext("mode"), space.newtext(mode))
-    return w_wrapper
+        if updating:
+            buffer_cls = W_BufferedRandom
+        elif writing or creating or appending:
+            buffer_cls = W_BufferedWriter
+        elif reading:
+            buffer_cls = W_BufferedReader
+        else:
+            raise oefmt(space.w_ValueError, "unknown mode: '%s'", mode)
+        w_buffer = space.call_function(
+            space.gettypefor(buffer_cls), w_raw, space.newint(buffering)
+        )
+        w_result = w_buffer
+        if binary:
+            return w_result
+
+        w_wrapper = space.call_function(space.gettypefor(W_TextIOWrapper),
+            w_buffer,
+            space.newtext_or_none(encoding),
+            space.newtext_or_none(errors),
+            space.newtext_or_none(newline),
+            space.newbool(line_buffering)
+        )
+        w_result = w_wrapper
+        space.setattr(w_wrapper, space.newtext("mode"), space.newtext(mode))
+        return w_result
+    except OperationError as e:
+        if w_result:
+            try:
+                space.call_method(w_result, "close")
+            except OperationError as e2:
+                e.chain_exceptions(space, e2)
+        raise
diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py
--- a/pypy/module/_io/interp_textio.py
+++ b/pypy/module/_io/interp_textio.py
@@ -1,6 +1,6 @@
 import sys
 
-from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.baseobjspace import W_Root, BufferInterfaceNotFound
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.gateway import WrappedDefault, interp2app, unwrap_spec
 from pypy.interpreter.typedef import (
@@ -290,7 +290,7 @@
 
     try:
         w_locale = space.call_method(space.builtin, '__import__',
-                                     space.newtext('locale'))
+                                     space.newtext('_bootlocale'))
         w_encoding = space.call_method(w_locale, 'getpreferredencoding',
                                        space.w_False)
     except OperationError as e:
@@ -528,13 +528,20 @@
 
     def close_w(self, space):
         self._check_attached(space)
-        if not space.is_true(space.getattr(self.w_buffer,
-                                           space.newtext("closed"))):
+        if space.is_true(space.getattr(self.w_buffer,
+                                       space.newtext("closed"))):
+            return
+        try:
+            space.call_method(self, "flush")
+        except OperationError as e:
             try:
-                space.call_method(self, "flush")
-            finally:
                 ret = space.call_method(self.w_buffer, "close")
-            return ret
+            except OperationError as e2:
+                e2.chain_exceptions(space, e)
+            raise
+        else:
+            ret = space.call_method(self.w_buffer, "close")
+        return ret
 
     def _dealloc_warn_w(self, space, w_source):
         space.call_method(self.w_buffer, "_dealloc_warn", w_source)
@@ -584,6 +591,10 @@
             # Given this, we know there was a valid snapshot point
             # len(dec_buffer) bytes ago with decoder state (b'', dec_flags).
             w_dec_buffer, w_dec_flags = space.unpackiterable(w_state, 2)
+            if not space.isinstance_w(w_dec_buffer, space.w_bytes):
+                msg = "decoder getstate() should have returned a bytes " \
+                      "object not '%T'"
+                raise oefmt(space.w_TypeError, msg, w_dec_buffer)
             dec_buffer = space.bytes_w(w_dec_buffer)
             dec_flags = space.int_w(w_dec_flags)
         else:
@@ -591,16 +602,18 @@
             dec_flags = 0
 
         # Read a chunk, decode it, and put the result in self._decoded_chars
-        w_input = space.call_method(self.w_buffer,
-                                    "read1" if self.has_read1 else "read",
+        func_name = "read1" if self.has_read1 else "read"
+        w_input = space.call_method(self.w_buffer, func_name,
                                     space.newint(self.chunk_size))
 
-        if not space.isinstance_w(w_input, space.w_bytes):
-            msg = "decoder getstate() should have returned a bytes " \
-                  "object not '%T'"
-            raise oefmt(space.w_TypeError, msg, w_input)
+        try:
+            input_buf = w_input.buffer_w(space, space.BUF_SIMPLE)
+        except BufferInterfaceNotFound:
+            msg = ("underlying %s() should have returned a bytes-like "
+                   "object, not '%T'")
+            raise oefmt(space.w_TypeError, msg, func_name, w_input)
 
-        eof = space.len_w(w_input) == 0
+        eof = input_buf.getlength() == 0
         w_decoded = space.call_method(self.w_decoder, "decode",
                                       w_input, space.newbool(eof))
         check_decoded(space, w_decoded)
@@ -611,7 +624,7 @@
         if self.telling:
             # At the snapshot point, len(dec_buffer) bytes before the read,
             # the next input to be decoded is dec_buffer + input_chunk.
-            next_input = dec_buffer + space.bytes_w(w_input)
+            next_input = dec_buffer + input_buf.as_str()
             self.snapshot = PositionSnapshot(dec_flags, next_input)
 
         return not eof
@@ -788,9 +801,10 @@
             text = space.unicode_w(w_text)
 
         needflush = False
+        text_needflush = False
         if self.write_through:
-            needflush = True
-        elif self.line_buffering and (haslf or text.find(u'\r') >= 0):
+            text_needflush = True
+        if self.line_buffering and (haslf or text.find(u'\r') >= 0):
             needflush = True
 
         # XXX What if we were just reading?
@@ -807,7 +821,8 @@
         self.pending_bytes.append(b)
         self.pending_bytes_count += len(b)
 
-        if self.pending_bytes_count > self.chunk_size or needflush:
+        if (self.pending_bytes_count > self.chunk_size or
+            needflush or text_needflush):
             self._writeflush(space)
 
         if needflush:
@@ -863,14 +878,18 @@
                               space.newtuple([space.newbytes(""),
                                               space.newint(cookie.dec_flags)]))
 
-    def _encoder_setstate(self, space, cookie):
-        if cookie.start_pos == 0 and cookie.dec_flags == 0:
+    def _encoder_reset(self, space, start_of_stream):
+        if start_of_stream:
             space.call_method(self.w_encoder, "reset")
             self.encoding_start_of_stream = True
         else:
             space.call_method(self.w_encoder, "setstate", space.newint(0))
             self.encoding_start_of_stream = False
 
+    def _encoder_setstate(self, space, cookie):
+        self._encoder_reset(space,
+                            cookie.start_pos == 0 and cookie.dec_flags == 0)
+
     @unwrap_spec(whence=int)
     def seek_w(self, space, w_pos, whence=0):
         self._check_attached(space)
@@ -898,8 +917,13 @@
             self.snapshot = None
             if self.w_decoder:
                 space.call_method(self.w_decoder, "reset")
-            return space.call_method(self.w_buffer, "seek",
-                                     w_pos, space.newint(whence))
+            w_res = space.call_method(self.w_buffer, "seek",
+                                      w_pos, space.newint(whence))
+            if self.w_encoder:
+                # If seek() == 0, we are at the start of stream
+                start_of_stream = space.eq_w(w_res, space.newint(0))
+                self._encoder_reset(space, start_of_stream)
+            return w_res
 
         elif whence != 0:
             raise oefmt(space.w_ValueError,
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
@@ -291,6 +291,39 @@
         raises(_io.UnsupportedOperation, bufio.seek, 0)
         raises(_io.UnsupportedOperation, bufio.tell)
 
+    def test_bufio_write_through(self):
+        import _io as io
+        # Issue #21396: write_through=True doesn't force a flush()
+        # on the underlying binary buffered object.
+        flush_called, write_called = [], []
+        class BufferedWriter(io.BufferedWriter):
+            def flush(self, *args, **kwargs):
+                flush_called.append(True)
+                return super().flush(*args, **kwargs)
+            def write(self, *args, **kwargs):
+                write_called.append(True)
+                return super().write(*args, **kwargs)
+
+        rawio = io.BytesIO()
+        data = b"a"
+        bufio = BufferedWriter(rawio, len(data)*2)
+        textio = io.TextIOWrapper(bufio, encoding='ascii',
+                                  write_through=True)
+        # write to the buffered io but don't overflow the buffer
+        text = data.decode('ascii')
+        textio.write(text)
+
+        # buffer.flush is not called with write_through=True
+        assert not flush_called
+        # buffer.write *is* called with write_through=True
+        assert write_called
+        assert rawio.getvalue() == b"" # no flush
+
+        write_called = [] # reset
+        textio.write(text * 10) # total content is larger than bufio buffer
+        assert write_called
+        assert rawio.getvalue() == data * 11 # all flushed
+
 class AppTestBufferedReaderWithThreads(AppTestBufferedReader):
     spaceconfig = dict(usemodules=['_io', 'thread', 'time'])
 
@@ -707,6 +740,7 @@
         pair = _io.BufferedRWPair(reader, writer)
         err = raises(NameError, pair.close)
         assert 'reader_non_existing' in str(err.value)
+        assert 'writer_non_existing' in str(err.value.__context__)
         assert not pair.closed
         assert not reader.closed
         assert not writer.closed
diff --git a/pypy/module/_io/test/test_fileio.py 
b/pypy/module/_io/test/test_fileio.py
--- a/pypy/module/_io/test/test_fileio.py
+++ b/pypy/module/_io/test/test_fileio.py
@@ -302,6 +302,36 @@
             return -1
         raises(ValueError, _io.FileIO, "foo", 'r', opener=opener)
 
+    def test_seek_bom(self):
+        # The BOM is not written again when seeking manually
+        import _io
+        filename = self.tmpfile + '_x3'
+        for charset in ('utf-8-sig', 'utf-16', 'utf-32'):
+            with _io.open(filename, 'w', encoding=charset) as f:
+                f.write('aaa')
+                pos = f.tell()
+            with _io.open(filename, 'r+', encoding=charset) as f:
+                f.seek(pos)
+                f.write('zzz')
+                f.seek(0)
+                f.write('bbb')
+            with _io.open(filename, 'rb') as f:
+                assert f.read() == 'bbbzzz'.encode(charset)
+
+    def test_seek_append_bom(self):
+        # Same test, but first seek to the start and then to the end
+        import _io, os
+        filename = self.tmpfile + '_x3'
+        for charset in ('utf-8-sig', 'utf-16', 'utf-32'):
+            with _io.open(filename, 'w', encoding=charset) as f:
+                f.write('aaa')
+            with _io.open(filename, 'a', encoding=charset) as f:
+                f.seek(0)
+                f.seek(0, os.SEEK_END)
+                f.write('xxx')
+            with _io.open(filename, 'rb') as f:
+                assert f.read() == 'aaaxxx'.encode(charset)
+
 
 def test_flush_at_exit():
     from pypy import conftest
diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py
--- a/pypy/module/_io/test/test_io.py
+++ b/pypy/module/_io/test/test_io.py
@@ -474,6 +474,22 @@
             assert f.mode == 'x'
         raises(FileExistsError, _io.open, filename, 'x')
 
+    def test_nonbuffered_textio(self):
+        import warnings, _io as io
+        filename = self.tmpfile + '_x2'
+        warnings.simplefilter("always", category=ResourceWarning)
+        with warnings.catch_warnings(record=True) as recorded:
+            raises(ValueError, io.open, filename, 'w', buffering=0)
+        assert recorded == []
+
+    def test_invalid_newline(self):
+        import warnings, _io as io
+        filename = self.tmpfile + '_x2'
+        warnings.simplefilter("always", category=ResourceWarning)
+        with warnings.catch_warnings(record=True) as recorded:
+            raises(ValueError, io.open, filename, 'w', newline='invalid')
+        assert recorded == []
+
 
 class AppTestIoAferClose:
     spaceconfig = dict(usemodules=['_io'])
diff --git a/pypy/module/_io/test/test_textio.py 
b/pypy/module/_io/test/test_textio.py
--- a/pypy/module/_io/test/test_textio.py
+++ b/pypy/module/_io/test/test_textio.py
@@ -1,5 +1,5 @@
 class AppTestTextIO:
-    spaceconfig = dict(usemodules=['_io', '_locale'])
+    spaceconfig = dict(usemodules=['_io', '_locale', 'array'])
 
     def setup_class(cls):
         from rpython.rlib.rarithmetic import INT_MAX, UINT_MAX
@@ -365,6 +365,22 @@
         raises(IOError, txt.close)  # exception not swallowed
         assert txt.closed
 
+    def test_close_error_on_close(self):
+        import _io as io
+        buffer = io.BytesIO(b'testdata')
+        def bad_flush():
+            raise OSError('flush')
+        def bad_close():
+            raise OSError('close')
+        buffer.close = bad_close
+        txt = io.TextIOWrapper(buffer, encoding="ascii")
+        txt.flush = bad_flush
+        err = raises(OSError, txt.close)
+        assert err.value.args == ('close',)
+        assert isinstance(err.value.__context__, OSError)
+        assert err.value.__context__.args == ('flush',)
+        assert not txt.closed
+
     def test_illegal_decoder(self):
         import _io
         raises(LookupError, _io.TextIOWrapper, _io.BytesIO(),
@@ -381,6 +397,38 @@
         t = _io.TextIOWrapper(NonbytesStream(u'a'))
         raises(TypeError, t.read)
 
+    def test_read_byteslike(self):
+        import _io as io
+        import array
+
+        class MemviewBytesIO(io.BytesIO):
+            '''A BytesIO object whose read method returns memoryviews
+               rather than bytes'''
+
+            def read1(self, len_):
+                return _to_memoryview(super().read1(len_))
+
+            def read(self, len_):
+                return _to_memoryview(super().read(len_))
+
+        def _to_memoryview(buf):
+            '''Convert bytes-object *buf* to a non-trivial memoryview'''
+
+            arr = array.array('i')
+            idx = len(buf) - len(buf) % arr.itemsize
+            arr.frombytes(buf[:idx])
+            return memoryview(arr)
+
+        r = MemviewBytesIO(b'Just some random string\n')
+        t = io.TextIOWrapper(r, 'utf-8')
+
+        # TextIOwrapper will not read the full string, because
+        # we truncate it to a multiple of the native int size
+        # so that we can construct a more complex memoryview.
+        bytes_val =  _to_memoryview(r.getvalue()).tobytes()
+
+        assert t.read(200) == bytes_val.decode('utf-8')
+
     def test_device_encoding(self):
         import os
         import sys
diff --git a/pypy/module/_posixsubprocess/_posixsubprocess.c 
b/pypy/module/_posixsubprocess/_posixsubprocess.c
--- a/pypy/module/_posixsubprocess/_posixsubprocess.c
+++ b/pypy/module/_posixsubprocess/_posixsubprocess.c
@@ -18,7 +18,19 @@
 #ifdef HAVE_SYS_SYSCALL_H
 #include <sys/syscall.h>
 #endif
+#if defined(HAVE_SYS_RESOURCE_H)
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_DIRENT_H
 #include <dirent.h>
+#endif
+
+#if defined(__ANDROID__) && !defined(SYS_getdents64)
+/* Android doesn't expose syscalls, add the definition manually. */
+# include <sys/linux-syscalls.h>
+# define SYS_getdents64  __NR_getdents64
+#endif
+
 #include "_posixsubprocess.h"
 
 #if defined(sun)
@@ -38,11 +50,7 @@
 # define FD_DIR "/proc/self/fd"
 #endif
 
-#define POSIX_CALL(call)   if ((call) == -1) goto error
-
-
-/* Maximum file descriptor, initialized on module load. */
-static long max_fd;
+#define POSIX_CALL(call)   do { if ((call) == -1) goto error; } while (0)
 
 
 /* Convert ASCII to a positive int, no libc call. no overflow. -1 on error. */
@@ -75,7 +83,7 @@
     if (stat("/dev", &dev_stat) != 0)
         return 0;
     if (stat(FD_DIR, &dev_fd_stat) != 0)
-        return 0; 
+        return 0;
     if (dev_stat.st_dev == dev_fd_stat.st_dev)
         return 0;  /* / == /dev == /dev/fd means it is static. #fail */
     return 1;
@@ -130,15 +138,47 @@
 }
 
 
-/* Close all file descriptors in the range start_fd inclusive to
- * end_fd exclusive except for those in py_fds_to_keep.  If the
- * range defined by [start_fd, end_fd) is large this will take a
- * long time as it calls close() on EVERY possible fd.
+/* Get the maximum file descriptor that could be opened by this process.
+ * This function is async signal safe for use between fork() and exec().
+ */
+static long
+safe_get_max_fd(void)
+{
+    long local_max_fd;
+#if defined(__NetBSD__)
+    local_max_fd = fcntl(0, F_MAXFD);
+    if (local_max_fd >= 0)
+        return local_max_fd;
+#endif
+#if defined(HAVE_SYS_RESOURCE_H) && defined(__OpenBSD__)
+    struct rlimit rl;
+    /* Not on the POSIX async signal safe functions list but likely
+     * safe.  TODO - Someone should audit OpenBSD to make sure. */
+    if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
+        return (long) rl.rlim_max;
+#endif
+#ifdef _SC_OPEN_MAX
+    local_max_fd = sysconf(_SC_OPEN_MAX);
+    if (local_max_fd == -1)
+#endif
+        local_max_fd = 256;  /* Matches legacy Lib/subprocess.py behavior. */
+    return local_max_fd;
+}
+
+
+/* Close all file descriptors in the range from start_fd and higher
+ * except for those in py_fds_to_keep.  If the range defined by
+ * [start_fd, safe_get_max_fd()) is large this will take a long
+ * time as it calls close() on EVERY possible fd.
+ *
+ * It isn't possible to know for sure what the max fd to go up to
+ * is for processes with the capability of raising their maximum.
  */
 static void
-_close_fds_by_brute_force(int start_fd, int end_fd, long *py_fds_to_keep,
+_close_fds_by_brute_force(long start_fd, long *py_fds_to_keep,
                          ssize_t num_fds_to_keep)
 {
+    long end_fd = safe_get_max_fd();
     ssize_t keep_seq_idx;
     int fd_num;
     /* As py_fds_to_keep is sorted we can loop through the list closing
@@ -148,13 +188,13 @@
         if (keep_fd < start_fd)
             continue;
         for (fd_num = start_fd; fd_num < keep_fd; ++fd_num) {
-            while (close(fd_num) < 0 && errno == EINTR);
+            close(fd_num);
         }
         start_fd = keep_fd + 1;
     }
     if (start_fd <= end_fd) {
         for (fd_num = start_fd; fd_num < end_fd; ++fd_num) {
-            while (close(fd_num) < 0 && errno == EINTR);
+            close(fd_num);
         }
     }
 }
@@ -175,8 +215,8 @@
    char           d_name[256];  /* Filename (null-terminated) */
 };
 
-/* Close all open file descriptors in the range start_fd inclusive to end_fd
- * exclusive. Do not close any in the sorted py_fds_to_keep list.
+/* Close all open file descriptors in the range from start_fd and higher
+ * Do not close any in the sorted py_fds_to_keep list.
  *
  * This version is async signal safe as it does not make any unsafe C library
  * calls, malloc calls or handle any locks.  It is _unfortunate_ to be forced
@@ -191,12 +231,10 @@
  * it with some cpp #define magic to work on other OSes as well if you want.
  */
 static void
-_close_open_fd_range_safe(int start_fd, int end_fd, long *py_fds_to_keep,
+_close_open_fds_safe(int start_fd, long *py_fds_to_keep,
                          ssize_t num_fds_to_keep)
 {
     int fd_dir_fd;
-    if (start_fd >= end_fd)
-        return;
 #ifdef O_CLOEXEC
     fd_dir_fd = open(FD_DIR, O_RDONLY | O_CLOEXEC, 0);
 #else
@@ -211,8 +249,7 @@
 #endif
     if (fd_dir_fd == -1) {
         /* No way to get a list of open fds. */
-       _close_fds_by_brute_force(start_fd, end_fd, py_fds_to_keep,
-                                 num_fds_to_keep);
+       _close_fds_by_brute_force(start_fd, py_fds_to_keep, num_fds_to_keep);
         return;
     } else {
         char buffer[sizeof(struct linux_dirent64)];
@@ -227,10 +264,10 @@
                 entry = (struct linux_dirent64 *)(buffer + offset);
                 if ((fd = _pos_int_from_ascii(entry->d_name)) < 0)
                     continue;  /* Not a number. */
-                if (fd != fd_dir_fd && fd >= start_fd && fd < end_fd &&
+                if (fd != fd_dir_fd && fd >= start_fd &&
                     !_is_fd_in_sorted_fd_sequence(
                        fd, py_fds_to_keep, num_fds_to_keep)) {
-                    while (close(fd) < 0 && errno == EINTR);
+                    close(fd);
                 }
             }
         }
@@ -238,13 +275,13 @@
     }
 }
 
-#define _close_open_fd_range _close_open_fd_range_safe
+#define _close_open_fds _close_open_fds_safe
 
 #else  /* NOT (defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)) */
 
 
-/* Close all open file descriptors in the range start_fd inclusive to end_fd
- * exclusive. Do not close any in the sorted py_fds_to_keep list.
+/* Close all open file descriptors from start_fd and higher.
+ * Do not close any in the sorted py_fds_to_keep list.
  *
  * This function violates the strict use of async signal safe functions. :(
  * It calls opendir(), readdir() and closedir().  Of these, the one most
@@ -257,26 +294,21 @@
  *   http://womble.decadent.org.uk/readdir_r-advisory.html
  */
 static void
-_close_open_fd_range_maybe_unsafe(int start_fd, int end_fd,
-                                  long *py_fds_to_keep, ssize_t 
num_fds_to_keep)
+_close_open_fds_maybe_unsafe(long start_fd,
+                            long *py_fds_to_keep, ssize_t num_fds_to_keep)
 {
     DIR *proc_fd_dir;
 #ifndef HAVE_DIRFD
-    while (_is_fd_in_sorted_fd_sequence(start_fd, py_fds_to_keep, 
num_fds_to_keep) &&
-           (start_fd < end_fd)) {
+    while (_is_fd_in_sorted_fd_sequence(start_fd, py_fds_to_keep, 
num_fds_to_keep)) {
         ++start_fd;
     }
-    if (start_fd >= end_fd)
-        return;
     /* Close our lowest fd before we call opendir so that it is likely to
      * reuse that fd otherwise we might close opendir's file descriptor in
      * our loop.  This trick assumes that fd's are allocated on a lowest
      * available basis. */
-    while (close(start_fd) < 0 && errno == EINTR);
+    close(start_fd);
     ++start_fd;
 #endif
-    if (start_fd >= end_fd)
-        return;
 
 #if defined(__FreeBSD__)
     if (!_is_fdescfs_mounted_on_dev_fd())
@@ -286,7 +318,7 @@
         proc_fd_dir = opendir(FD_DIR);
     if (!proc_fd_dir) {
         /* No way to get a list of open fds. */
-        _close_fds_by_brute_force(start_fd, end_fd, py_fds_to_keep, 
num_fds_to_keep);
+        _close_fds_by_brute_force(start_fd, py_fds_to_keep, num_fds_to_keep);
     } else {
         struct dirent *dir_entry;
 #ifdef HAVE_DIRFD
@@ -299,22 +331,22 @@
             int fd;
             if ((fd = _pos_int_from_ascii(dir_entry->d_name)) < 0)
                 continue;  /* Not a number. */
-            if (fd != fd_used_by_opendir && fd >= start_fd && fd < end_fd &&
+            if (fd != fd_used_by_opendir && fd >= start_fd &&
                 !_is_fd_in_sorted_fd_sequence(fd, py_fds_to_keep, 
num_fds_to_keep)) {
-                while (close(fd) < 0 && errno == EINTR);
+                close(fd);
             }
             errno = 0;
         }
         if (errno) {
             /* readdir error, revert behavior. Highly Unlikely. */
             _close_fds_by_brute_force(
-               start_fd, end_fd, py_fds_to_keep, num_fds_to_keep);
+               start_fd, py_fds_to_keep, num_fds_to_keep);
         }
         closedir(proc_fd_dir);
     }
 }
 
-#define _close_open_fd_range _close_open_fd_range_maybe_unsafe
+#define _close_open_fds _close_open_fds_maybe_unsafe
 
 #endif  /* else NOT (defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)) */
 
@@ -357,15 +389,12 @@
         goto error;
 
     /* Close parent's pipe ends. */
-    if (p2cwrite != -1) {
+    if (p2cwrite != -1)
         POSIX_CALL(close(p2cwrite));
-    }
-    if (c2pread != -1) {
+    if (c2pread != -1)
         POSIX_CALL(close(c2pread));
-    }
-    if (errread != -1) {
+    if (errread != -1)
         POSIX_CALL(close(errread));
-    }
     POSIX_CALL(close(errpipe_read));
 
     /* When duping fds, if there arises a situation where one of the fds is
@@ -401,15 +430,12 @@
 
     /* Close pipe fds.  Make sure we don't close the same fd more than */
     /* once, or standard fds. */
-    if (p2cread > 2) {
+    if (p2cread > 2)
         POSIX_CALL(close(p2cread));
-    }
-    if (c2pwrite > 2 && c2pwrite != p2cread) {
+    if (c2pwrite > 2 && c2pwrite != p2cread)
         POSIX_CALL(close(c2pwrite));
-    }
-    if (errwrite != c2pwrite && errwrite != p2cread && errwrite > 2) {
+    if (errwrite != c2pwrite && errwrite != p2cread && errwrite > 2)
         POSIX_CALL(close(errwrite));
-    }
 
     if (cwd)
         POSIX_CALL(chdir(cwd));
@@ -441,14 +467,8 @@
 
     /* close FDs after executing preexec_fn, which might open FDs */
     if (close_fds) {
-        int local_max_fd = max_fd;
-#if defined(__NetBSD__)
-        local_max_fd = fcntl(0, F_MAXFD);
-        if (local_max_fd < 0)
-            local_max_fd = max_fd;
-#endif
         /* TODO HP-UX could use pstat_getproc() if anyone cares about it. */
-        _close_open_fd_range(3, local_max_fd, py_fds_to_keep, num_fds_to_keep);
+        _close_open_fds(3, py_fds_to_keep, num_fds_to_keep);
     }
 
     /* This loop matches the Lib/os.py _execvpe()'s PATH search when */
@@ -491,7 +511,7 @@
         /* We can't call strerror(saved_errno).  It is not async signal safe.
          * The parent process will look the error message up. */
     } else {
-        unused = write(errpipe_write, "RuntimeError:0:", 15);
+        unused = write(errpipe_write, "SubprocessError:0:", 18);
         unused = write(errpipe_write, err_msg, strlen(err_msg));
     }
     if (unused) return;  /* silly? yes! avoids gcc compiler warning. */
@@ -579,9 +599,4 @@
 void
 pypy_subprocess_init(void)
 {
-#ifdef _SC_OPEN_MAX
-    max_fd = sysconf(_SC_OPEN_MAX);
-    if (max_fd == -1)
-#endif
-        max_fd = 256;  /* Matches Lib/subprocess.py */
 }
diff --git a/pypy/module/_posixsubprocess/interp_subprocess.py 
b/pypy/module/_posixsubprocess/interp_subprocess.py
--- a/pypy/module/_posixsubprocess/interp_subprocess.py
+++ b/pypy/module/_posixsubprocess/interp_subprocess.py
@@ -36,6 +36,15 @@
 if config['HAVE_SETSID']:
     compile_extra.append("-DHAVE_SETSID")
 
+class CConfig:
+    _compilation_info_ = ExternalCompilationInfo(includes=['dirent.h'])
+    HAVE_DIRENT_H = platform.Has("opendir")
+
+config = platform.configure(CConfig)
+
+if config['HAVE_DIRENT_H']:
+    compile_extra.append("-DHAVE_DIRENT_H")
+
 eci = eci.merge(
     rposix.eci_inheritable,
     ExternalCompilationInfo(
diff --git a/pypy/module/_vmprof/test/test_direct.py 
b/pypy/module/_vmprof/test/test_direct.py
--- a/pypy/module/_vmprof/test/test_direct.py
+++ b/pypy/module/_vmprof/test/test_direct.py
@@ -1,4 +1,4 @@
-
+import sys
 import py
 try:
     import cffi
@@ -7,6 +7,7 @@
 
 from rpython.rlib import rvmprof
 srcdir = py.path.local(rvmprof.__file__).join("..", "src")
+shareddir = srcdir.join('shared')
 
 ffi = cffi.FFI()
 ffi.cdef("""
@@ -43,7 +44,7 @@
 }
 
 
-""" + open(str(srcdir.join("shared/vmprof_get_custom_offset.h"))).read(), 
include_dirs=[str(srcdir)])
+""" + open(str(srcdir.join("shared/vmprof_get_custom_offset.h"))).read(), 
include_dirs=[str(srcdir), str(shareddir)])
 
 class TestDirect(object):
     def test_infrastructure(self):
diff --git a/pypy/module/posix/interp_posix.py 
b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -419,11 +419,11 @@
     """
     while True:
         try:
-            res = rposix.posix_fadvise(fd, offset, length, advice)
+            rposix.posix_fadvise(fd, offset, length, advice)
         except OSError as e:
             wrap_oserror(space, e, eintr_retry=True)
         else:
-            return space.newint(res)
+            return
 
 # ____________________________________________________________
 
diff --git a/pypy/module/posix/test/test_posix2.py 
b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -862,23 +862,19 @@
 
     if hasattr(rposix, 'posix_fadvise'):
         def test_os_posix_fadvise(self):
-            posix, os = self.posix, self.os
-            localdir = os.getcwd()
-            os.mkdir(self.path2 + 'test_os_posix_fadvise')
+            posix = self.posix
+            fd = posix.open(self.path2 + 'test_os_posix_fadvise', 
posix.O_CREAT | posix.O_RDWR)
             try:
-                fd = os.open(self.path2 + 'test_os_posix_fadvise', os.O_RDONLY)
-                try:
-                    mypath = os.getcwd()
-                    assert posix.posix_fadvise(fd, 0, 0, 
posix.POSIX_FADV_WILLNEED) == 0
-                    assert posix.posix_fadvise(fd, 0, 0, 
posix.POSIX_FADV_NORMAL) == 0
-                    assert posix.posix_fadvise(fd, 0, 0, 
posix.POSIX_FADV_SEQUENTIAL) == 0
-                    assert posix.posix_fadvise(fd, 0, 0, 
posix.POSIX_FADV_RANDOM) == 0
-                    assert posix.posix_fadvise(fd, 0, 0, 
posix.POSIX_FADV_NOREUSE) == 0
-                    assert posix.posix_fadvise(fd, 0, 0, 
posix.POSIX_FADV_DONTNEED) == 0
-                finally:
-                    os.close(fd)
+                posix.write(fd, b"foobar")
+                assert posix.posix_fadvise(fd, 0, 1, 
posix.POSIX_FADV_WILLNEED) is None
+                assert posix.posix_fadvise(fd, 1, 1, posix.POSIX_FADV_NORMAL) 
is None
+                assert posix.posix_fadvise(fd, 2, 1, 
posix.POSIX_FADV_SEQUENTIAL) is None
+                assert posix.posix_fadvise(fd, 3, 1, posix.POSIX_FADV_RANDOM) 
is None
+                assert posix.posix_fadvise(fd, 4, 1, posix.POSIX_FADV_NOREUSE) 
is None
+                assert posix.posix_fadvise(fd, 5, 1, 
posix.POSIX_FADV_DONTNEED) is None
+                raises(OSError, posix.posix_fadvise, fd, 6, 1, 1234567)
             finally:
-                os.chdir(localdir)
+                posix.close(fd)
 
     if hasattr(rposix, 'posix_fallocate'):
         def test_os_posix_posix_fallocate(self):
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
@@ -3,7 +3,7 @@
 The 'sys' module.
 """
 
-from _structseq import structseqtype, structseqfield
+from _structseq import structseqtype, structseqfield, SimpleNamespace
 import sys
 import _imp
 
@@ -111,41 +111,6 @@
 null__xoptions = {}
 
 
-class SimpleNamespace:
-    """A simple attribute-based namespace.
-
-SimpleNamespace(**kwargs)"""
-
-    def __init__(self, **kwargs):
-        self.__dict__.update(kwargs)
-
-    def __repr__(self):
-        ident = id(self)
-        if ident in sns_recurse:
-            return "namespace(...)"
-        sns_recurse.add(ident)
-        try:
-            pairs = ('%s=%r' % item for item in sorted(self.__dict__.items()))
-            return "namespace(%s)" % ', '.join(pairs)
-        finally:
-            sns_recurse.discard(ident)
-
-    def __eq__(self, other):
-        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'
-
-
 implementation = SimpleNamespace(
     name='pypy',
     version=sys.version_info,
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py 
b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
@@ -596,3 +596,37 @@
 
         get_data.errcheck = ret_list_p(1)
         assert get_data('testing!') == [-1, -2, -3, -4]
+
+    def test_issue2533(self):
+        import cffi
+        ffi = cffi.FFI()
+        ffi.cdef("int **fetchme(void);")
+        ffi.set_source("_x_cffi", """
+            int **fetchme(void)
+            {
+                static int a = 42;
+                static int *pa = &a;
+                return &pa;
+            }
+        """)
+        from rpython.tool.udir import udir
+        ffi.compile(verbose=True, tmpdir=str(udir))
+
+        import sys
+        sys.path.insert(0, str(udir))
+        try:
+            from _x_cffi import ffi, lib
+        finally:
+            sys.path.pop(0)
+        fetchme = ffi.addressof(lib, 'fetchme')
+        fetchme = int(ffi.cast("intptr_t", fetchme))
+
+        FN = CFUNCTYPE(POINTER(POINTER(c_int)))
+        ff = cast(fetchme, FN)
+
+        g = ff()
+        assert g.contents.contents.value == 42
+
+        h = c_int(43)
+        g[0] = pointer(h)     # used to crash here
+        assert g.contents.contents.value == 43
diff --git a/pypy/module/time/app_time.py b/pypy/module/time/app_time.py
--- a/pypy/module/time/app_time.py
+++ b/pypy/module/time/app_time.py
@@ -1,7 +1,6 @@
 # NOT_RPYTHON
 
-from _structseq import structseqtype, structseqfield
-from types import SimpleNamespace
+from _structseq import structseqtype, structseqfield, SimpleNamespace
 import time
 
 class struct_time(metaclass=structseqtype):
diff --git a/pypy/objspace/std/dictmultiobject.py 
b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -143,11 +143,7 @@
         init_or_update(space, self, __args__, 'dict')
 
     def descr_repr(self, space):
-        ec = space.getexecutioncontext()
-        w_currently_in_repr = ec._py_repr
-        if w_currently_in_repr is None:
-            w_currently_in_repr = ec._py_repr = space.newdict()
-        return dictrepr(space, w_currently_in_repr, self)
+        return dictrepr(space, space.get_objects_in_repr(), self)
 
     def descr_eq(self, space, w_other):
         if space.is_w(self, w_other):
@@ -404,10 +400,9 @@
     def dictrepr(currently_in_repr, d):
         if len(d) == 0:
             return "{}"
-        dict_id = id(d)
-        if dict_id in currently_in_repr:
+        if d in currently_in_repr:
             return '{...}'
-        currently_in_repr[dict_id] = 1
+        currently_in_repr[d] = 1
         try:
             items = []
             # XXX for now, we cannot use items() without list at
@@ -419,7 +414,7 @@
             return "{" +  ', '.join(items) + "}"
         finally:
             try:
-                del currently_in_repr[dict_id]
+                del currently_in_repr[d]
             except:
                 pass
 ''', filename=__file__)
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -23,6 +23,7 @@
     WrappedDefault, applevel, interp2app, unwrap_spec)
 from pypy.interpreter.signature import Signature
 from pypy.interpreter.typedef import TypeDef
+from pypy.interpreter.miscutils import StringSort
 from pypy.objspace.std.bytesobject import W_BytesObject
 from pypy.objspace.std.floatobject import W_FloatObject
 from pypy.objspace.std.intobject import W_IntObject
@@ -438,11 +439,7 @@
     def descr_repr(self, space):
         if self.length() == 0:
             return space.newtext('[]')
-        ec = space.getexecutioncontext()
-        w_currently_in_repr = ec._py_repr
-        if w_currently_in_repr is None:
-            w_currently_in_repr = ec._py_repr = space.newdict()
-        return listrepr(space, w_currently_in_repr, self)
+        return listrepr(space, space.get_objects_in_repr(), self)
 
     def descr_eq(self, space, w_other):
         if not isinstance(w_other, W_ListObject):
@@ -2014,15 +2011,14 @@
 app = applevel("""
     def listrepr(currently_in_repr, l):
         'The app-level part of repr().'
-        list_id = id(l)
-        if list_id in currently_in_repr:
+        if l in currently_in_repr:
             return '[...]'
-        currently_in_repr[list_id] = 1
+        currently_in_repr[l] = 1
         try:
             return "[" + ", ".join([repr(x) for x in l]) + ']'
         finally:
             try:
-                del currently_in_repr[list_id]
+                del currently_in_repr[l]
             except:
                 pass
 """, filename=__file__)
@@ -2039,7 +2035,6 @@
 IntBaseTimSort = make_timsort_class()
 FloatBaseTimSort = make_timsort_class()
 IntOrFloatBaseTimSort = make_timsort_class()
-StringBaseTimSort = make_timsort_class()
 UnicodeBaseTimSort = make_timsort_class()
 
 
@@ -2076,11 +2071,6 @@
         return fa < fb
 
 
-class StringSort(StringBaseTimSort):
-    def lt(self, a, b):
-        return a < b
-
-
 class UnicodeSort(UnicodeBaseTimSort):
     def lt(self, a, b):
         return a < b
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -126,6 +126,14 @@
         ec._py_repr = None
         return ec
 
+    def get_objects_in_repr(self):
+        from pypy.module.__pypy__.interp_identitydict import W_IdentityDict
+        ec = self.getexecutioncontext()
+        w_currently_in_repr = ec._py_repr
+        if w_currently_in_repr is None:
+            w_currently_in_repr = ec._py_repr = W_IdentityDict(self)
+        return w_currently_in_repr
+
     def gettypefor(self, cls):
         return self.gettypeobject(cls.typedef)
 
diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py
--- a/pypy/objspace/std/setobject.py
+++ b/pypy/objspace/std/setobject.py
@@ -165,11 +165,7 @@
         _initialize_set(space, self, w_iterable)
 
     def descr_repr(self, space):
-        ec = space.getexecutioncontext()
-        w_currently_in_repr = ec._py_repr
-        if w_currently_in_repr is None:
-            w_currently_in_repr = ec._py_repr = space.newdict()
-        return setrepr(space, w_currently_in_repr, self)
+        return setrepr(space, space.get_objects_in_repr(), self)
 
     def descr_eq(self, space, w_other):
         if isinstance(w_other, W_BaseSetObject):
@@ -1700,10 +1696,9 @@
 app = gateway.applevel("""
     def setrepr(currently_in_repr, s):
         'The app-level part of repr().'
-        set_id = id(s)
-        if set_id in currently_in_repr:
+        if s in currently_in_repr:
             return '%s(...)' % (s.__class__.__name__,)
-        currently_in_repr[set_id] = 1
+        currently_in_repr[s] = 1
         try:
             if not s:
                 return '%s()' % (s.__class__.__name__,)
@@ -1714,7 +1709,7 @@
                 return '%s({%s})' % (s.__class__.__name__, listrepr[1:-1])
         finally:
             try:
-                del currently_in_repr[set_id]
+                del currently_in_repr[s]
             except:
                 pass
 """, filename=__file__)
diff --git a/pypy/objspace/std/sliceobject.py b/pypy/objspace/std/sliceobject.py
--- a/pypy/objspace/std/sliceobject.py
+++ b/pypy/objspace/std/sliceobject.py
@@ -253,7 +253,7 @@
 
 
 app = gateway.applevel("""
-    from operator import index
+    from _operator import index
 
     def evaluate_slice_index(x):
         try:
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -1087,7 +1087,7 @@
     return w_name.text_w(space)
 
 def create_all_slots(w_self, hasoldstylebase, w_bestbase, force_new_layout):
-    from pypy.objspace.std.listobject import StringSort
+    from pypy.interpreter.miscutils import string_sort
 
     base_layout = w_bestbase.layout
     index_next_extra_slot = base_layout.nslots
@@ -1120,8 +1120,7 @@
             else:
                 newslotnames.append(slot_name)
         # Sort the list of names collected so far
-        sorter = StringSort(newslotnames, len(newslotnames))
-        sorter.sort()
+        string_sort(newslotnames)
         # Try to create all slots in order.  The creation of some of
         # them might silently fail; then we delete the name from the
         # list.  At the end, 'index_next_extra_slot' has been advanced
diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -241,12 +241,14 @@
             zf.close()
         else:
             archive = str(builddir.join(name + '.tar.bz2'))
-            if sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
+            if sys.platform == 'darwin':
                 print >>sys.stderr, """Warning: tar on current platform does 
not suport overriding the uid and gid
 for its contents. The tarball will contain your uid and gid. If you are
 building the actual release for the PyPy website, you may want to be
 using another platform..."""
                 e = os.system('tar --numeric-owner -cvjf ' + archive + " " + 
name)
+            elif sys.platform.startswith('freebsd'):
+                e = os.system('tar --uname=root --gname=wheel -cvjf ' + 
archive + " " + name)
             elif sys.platform == 'cygwin':
                 e = os.system('tar --owner=Administrator 
--group=Administrators --numeric-owner -cvjf ' + archive + " " + name)
             else:
diff --git a/rpython/jit/backend/llsupport/asmmemmgr.py 
b/rpython/jit/backend/llsupport/asmmemmgr.py
--- a/rpython/jit/backend/llsupport/asmmemmgr.py
+++ b/rpython/jit/backend/llsupport/asmmemmgr.py
@@ -250,7 +250,7 @@
         return self.rawstart
 
     def overwrite(self, index, char):
-        assert 0 <= index < self.get_relative_pos()
+        assert 0 <= index < self.get_relative_pos(break_basic_block=False)
         block = self._cursubblock
         index -= self._baserelpos
         while index < 0:
@@ -264,7 +264,8 @@
         self.overwrite(index + 2, chr((val >> 16) & 0xff))
         self.overwrite(index + 3, chr((val >> 24) & 0xff))
 
-    def get_relative_pos(self):
+    def get_relative_pos(self, break_basic_block=True):
+        # 'break_basic_block' is only used in x86
         return self._baserelpos + self._cursubindex
 
     def copy_to_raw_memory(self, addr):
@@ -288,7 +289,7 @@
         HEX = '0123456789ABCDEF'
         dump = []
         src = rffi.cast(rffi.CCHARP, addr)
-        end = self.get_relative_pos()
+        end = self.get_relative_pos(break_basic_block=False)
         if count != -1:
             end = offset + count
         for p in range(offset, end):
@@ -336,17 +337,20 @@
 
     def _become_a_plain_block_builder(self):
         # hack purely for speed of tests
-        self._data = []
-        self.writechar = self._data.append
-        self.overwrite = self._data.__setitem__
-        self.get_relative_pos = self._data.__len__
+        self._data = _data = []
+        self.writechar = _data.append
+        self.overwrite = _data.__setitem__
+        def get_relative_pos(break_basic_block=True):
+            return len(_data)
+        self.get_relative_pos = get_relative_pos
         def plain_copy_to_raw_memory(addr):
             dst = rffi.cast(rffi.CCHARP, addr)
-            for i, c in enumerate(self._data):
+            for i, c in enumerate(_data):
                 dst[i] = c
         self._copy_to_raw_memory = plain_copy_to_raw_memory
 
     def insert_gcroot_marker(self, mark):
         if self.gcroot_markers is None:
             self.gcroot_markers = []
-        self.gcroot_markers.append((self.get_relative_pos(), mark))
+        self.gcroot_markers.append(
+            (self.get_relative_pos(break_basic_block=False), mark))
diff --git a/rpython/jit/backend/llsupport/assembler.py 
b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -265,14 +265,16 @@
 
     def enter_portal_frame(self, op):
         if self.cpu.HAS_CODEMAP:
+            pos = self.mc.get_relative_pos(break_basic_block=False)
             self.codemap_builder.enter_portal_frame(op.getarg(0).getint(),
                                                     op.getarg(1).getint(),
-                                                    self.mc.get_relative_pos())
+                                                    pos)
 
     def leave_portal_frame(self, op):
         if self.cpu.HAS_CODEMAP:
+            pos = self.mc.get_relative_pos(break_basic_block=False)
             self.codemap_builder.leave_portal_frame(op.getarg(0).getint(),
-                                                    self.mc.get_relative_pos())
+                                                    pos)
 
     def call_assembler(self, op, argloc, vloc, result_loc, tmploc):
         """
diff --git a/rpython/jit/backend/x86/assembler.py 
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -76,6 +76,7 @@
         BaseAssembler.setup(self, looptoken)
         assert self.memcpy_addr != 0, "setup_once() not called?"
         self.current_clt = looptoken.compiled_loop_token
+        self.pending_slowpaths = []
         self.pending_guard_tokens = []
         if WORD == 8:
             self.pending_memoryerror_trampoline_from = []
@@ -95,6 +96,7 @@
             self.pending_memoryerror_trampoline_from = None
         self.mc = None
         self.current_clt = None
+        self.frame_depth_to_patch = None
 
     def _build_float_constants(self):
         # 0x80000000000000008000000000000000
@@ -181,6 +183,7 @@
         """ This builds a general call slowpath, for whatever call happens to
         come.
         """
+        self.pending_slowpaths = []
         mc = codebuf.MachineCodeBlockWrapper()
         # copy registers to the frame, with the exception of the
         # 'cond_call_register_arguments' and eax, because these have already
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to