[pypy-commit] pypy default: merge upstream

pjenvey noreply at buildbot.pypy.org
Thu Sep 11 22:48:39 CEST 2014


Author: Philip Jenvey <pjenvey at underboss.org>
Branch: 
Changeset: r73480:a552e9ed86d6
Date: 2014-09-11 12:43 -0700
http://bitbucket.org/pypy/pypy/changeset/a552e9ed86d6/

Log:	merge upstream

diff too long, truncating to 2000 out of 2511 lines

diff --git a/_pytest/resultlog.py b/_pytest/resultlog.py
--- a/_pytest/resultlog.py
+++ b/_pytest/resultlog.py
@@ -54,15 +54,16 @@
         self.logfile = logfile # preferably line buffered
 
     def write_log_entry(self, testpath, lettercode, longrepr, sections=None):
-        py.builtin.print_("%s %s" % (lettercode, testpath), file=self.logfile)
+        _safeprint("%s %s" % (lettercode, testpath), file=self.logfile)
         for line in longrepr.splitlines():
-            py.builtin.print_(" %s" % line, file=self.logfile)
-        if sections is not None:
+            _safeprint(" %s" % line, file=self.logfile)
+        if sections is not None and (
+                lettercode in ('E', 'F')):    # to limit the size of logs
             for title, content in sections:
-                py.builtin.print_(" ---------- %s ----------" % (title,),
-                                  file=self.logfile)
+                _safeprint(" ---------- %s ----------" % (title,),
+                           file=self.logfile)
                 for line in content.splitlines():
-                    py.builtin.print_(" %s" % line, file=self.logfile)
+                    _safeprint(" %s" % line, file=self.logfile)
 
     def log_outcome(self, report, lettercode, longrepr):
         testpath = getattr(report, 'nodeid', None)
@@ -105,3 +106,8 @@
         if path is None:
             path = "cwd:%s" % py.path.local()
         self.write_log_entry(path, '!', str(excrepr))
+
+def _safeprint(s, file):
+    if isinstance(s, unicode):
+        s = s.encode('utf-8')
+    py.builtin.print_(s, file=file)
diff --git a/lib-python/2.7/test/test_mmap.py b/lib-python/2.7/test/test_mmap.py
--- a/lib-python/2.7/test/test_mmap.py
+++ b/lib-python/2.7/test/test_mmap.py
@@ -179,25 +179,27 @@
         import sys
         f = open(TESTFN, "r+b")
         try:
-            m = mmap.mmap(f.fileno(), mapsize+1)
-        except ValueError:
-            # we do not expect a ValueError on Windows
-            # CAUTION:  This also changes the size of the file on disk, and
-            # later tests assume that the length hasn't changed.  We need to
-            # repair that.
+            try:
+                m = mmap.mmap(f.fileno(), mapsize+1)
+            except ValueError:
+                # we do not expect a ValueError on Windows
+                # CAUTION:  This also changes the size of the file on disk, and
+                # later tests assume that the length hasn't changed.  We need to
+                # repair that.
+                if sys.platform.startswith('win'):
+                    self.fail("Opening mmap with size+1 should work on Windows.")
+            else:
+                # we expect a ValueError on Unix, but not on Windows
+                if not sys.platform.startswith('win'):
+                    self.fail("Opening mmap with size+1 should raise ValueError.")
+                m.close()
+        finally:
+            f.close()
             if sys.platform.startswith('win'):
-                self.fail("Opening mmap with size+1 should work on Windows.")
-        else:
-            # we expect a ValueError on Unix, but not on Windows
-            if not sys.platform.startswith('win'):
-                self.fail("Opening mmap with size+1 should raise ValueError.")
-            m.close()
-        f.close()
-        if sys.platform.startswith('win'):
-            # Repair damage from the resizing test.
-            f = open(TESTFN, 'r+b')
-            f.truncate(mapsize)
-            f.close()
+                # Repair damage from the resizing test.
+                f = open(TESTFN, 'r+b')
+                f.truncate(mapsize)
+                f.close()
 
         # Opening mmap with access=ACCESS_WRITE
         f = open(TESTFN, "r+b")
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -65,9 +65,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '2.3'
+version = '2.4'
 # The full version, including alpha/beta/rc tags.
-release = '2.3.0'
+release = '2.4.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst
--- a/pypy/doc/getting-started-python.rst
+++ b/pypy/doc/getting-started-python.rst
@@ -111,6 +111,10 @@
    of your choice.  Typical example: ``--opt=2`` gives a good (but of
    course slower) Python interpreter without the JIT.
 
+   Consider using PyPy instead of CPython in the above command line,
+   as it is much faster.  (Note that ``rpython`` is a Python 2 program,
+   not Python 3; you need to run either PyPy 2 or CPython 2.)
+
 .. _`optimization level`: config/opt.html
 
 If everything works correctly this will create an executable
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-2.4.0.rst
    release-2.3.1.rst
    release-2.3.0.rst
    release-2.2.1.rst
diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst
--- a/pypy/doc/index.rst
+++ b/pypy/doc/index.rst
@@ -40,7 +40,7 @@
 
 * `FAQ`_: some frequently asked questions.
 
-* `Release 2.3.1`_: the latest official release
+* `Release 2.4.0`_: the latest official release
 
 * `PyPy Blog`_: news and status info about PyPy 
 
@@ -110,7 +110,7 @@
 .. _`Getting Started`: getting-started.html
 .. _`Papers`: extradoc.html
 .. _`Videos`: video-index.html
-.. _`Release 2.3.1`: http://pypy.org/download.html
+.. _`Release 2.4.0`: http://pypy.org/download.html
 .. _`speed.pypy.org`: http://speed.pypy.org
 .. _`RPython toolchain`: translation.html
 .. _`potential project ideas`: project-ideas.html
diff --git a/pypy/doc/release-2.4.0.rst b/pypy/doc/release-2.4.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-2.4.0.rst
@@ -0,0 +1,119 @@
+=================================================
+PyPy 2.4 - Snow White
+=================================================
+
+We're pleased to announce PyPy 2.4, which contains significant performance
+enhancements and bug fixes. 
+
+You can already download the PyPy 2.4-beta1 pre-release here:
+
+    http://pypy.org/download.html
+
+We would like to thank our donors for the continued support of the PyPy
+project, and for those who donate to our three sub-projects.
+We've shown quite a bit of progress, but we're slowly running out of funds.
+Please consider donating more, or even better convince your employer to donate,
+so we can finish those projects! We would like to also point out that in
+September, `the Python Software Foundation`_ will `match funds`_ for
+any donations up to $10k!  The three sub-projects are:
+
+* `Py3k`_ (supporting Python 3.x): We have released a Python 3.2.5 compatible version
+   we call PyPy3 2.3.1, and are working toward a Python 3.3 compatible version
+
+* `STM`_ (software transactional memory): We have released a first working version,
+  and continue to try out new promising paths of achieving a fast multithreaded Python
+
+* `NumPy`_ which requires installation of our fork of upstream numpy, 
+  available `on bitbucket`_
+
+.. _`Py3k`: http://pypy.org/py3donate.html
+.. _`STM`: http://pypy.org/tmdonate2.html
+.. _`NumPy`: http://pypy.org/numpydonate.html
+.. _`on bitbucket`: https://www.bitbucket.org/pypy/numpy   
+.. _`the Python Software Foundation`: https://www.python.org/psf/
+.. _`match funds`: http://morepypy.blogspot.com/2014/09/python-software-foundation-matching.html
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 2.4 and cpython 2.7.x`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports **x86** machines on most common operating systems 
+(Linux 32/64, Mac OS X 64, Windows, and OpenBSD),
+as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux. 
+
+While we support 32 bit python on Windows, work on the native Windows 64
+bit python is still stalling, we would welcome a volunteer
+to `handle that`_.
+
+.. _`pypy 2.4 and cpython 2.7.x`: http://speed.pypy.org
+.. _`handle that`: http://doc.pypy.org/en/latest/windows.html#what-is-missing-for-a-full-64-bit-translation
+
+Highlights
+==========
+
+Benchmarks improved after internal enhancements in string and
+bytearray handling, and a major rewrite of the GIL handling. This means
+that external calls are now a lot faster, especially the CFFI ones. It also
+means better performance in a lot of corner cases with handling strings or
+bytearrays. The main bugfix is handling of many socket objects in your
+program which in the long run used to "leak" memory.
+
+PyPy now uses Python 2.7.8 standard library.
+
+We welcomed more than 12 new contributors, and conducted two Google
+Summer of Code projects, as well as other student projects not
+directly related to Summer of Code.
+
+
+Issues reported with our previous release were fixed after reports from users on
+our new issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at
+#pypy. Here is a summary of the user-facing changes;
+for more information see `whats-new`_:
+
+* Reduced internal copying of bytearray operations
+
+* Tweak the internal structure of StringBuilder to speed up large string
+  handling, which becomes advantageous on large programs at the cost of slightly
+  slower small *benchmark* type programs.
+
+* Boost performance of thread-local variables in both unjitted and jitted code,
+  this mostly affects errno handling on linux, which makes external calls
+  faster.
+
+* Move to a mixed polling and mutex GIL model that make mutlithreaded jitted
+  code run *much* faster
+
+* Optimize errno handling in linux (x86 and x86-64 only)
+
+* Remove ctypes pythonapi and ctypes.PyDLL, which never worked on PyPy
+
+* Fix performance regression on ufunc(<scalar>, <scalar>) in numpy
+
+* Classes in the ast module are now distinct from structures used by
+  the compiler, which simplifies and speeds up translation of our
+  source code to the PyPy binary interpreter
+
+* Upgrade stdlib from 2.7.5 to 2.7.8
+
+* Win32 now links statically to zlib, expat, bzip, and openssl-1.0.1i.
+  No more missing DLLs
+  
+* Many issues were resolved_ since the 2.3.1 release on June 8
+
+.. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.3.1.html
+.. _resolved: https://bitbucket.org/pypy/pypy/issues?status=resolved
+
+We have further improvements on the way: rpython file handling,
+numpy linalg compatibility, as well
+as improved GC and many smaller improvements.
+
+Please try it out and let us know what you think. We especially welcome
+success stories, we know you are using PyPy, please tell us about it!
+
+Cheers
+
+The PyPy Team
+
diff --git a/pypy/doc/release-2.4.rst b/pypy/doc/release-2.4.rst
deleted file mode 100644
--- a/pypy/doc/release-2.4.rst
+++ /dev/null
@@ -1,107 +0,0 @@
-=================================================
-PyPy 2.4 - ????????
-=================================================
-
-We're pleased to announce PyPy 2.4, a significant milestone on it's own right
-and the proud parent of our recent PyPy3 and STM releases.
-
-This release contains several improvements and bugfixes.
-
-You can download the PyPy 2.4 release here:
-
-    http://pypy.org/download.html
-
-We would like to thank our donors for the continued support of the PyPy
-project, and for those who donate to our three sub-projects.
-We've shown quite a bit of progress 
-but we're slowly running out of funds.
-Please consider donating more, or even better convince your employer to donate,
-so we can finish those projects!  The three sub-projects are:
-
-* `Py3k`_ (supporting Python 3.x): We have released a Python 3.2.5 compatable version
-   we call PyPy3 2.3.1, and are working toward a Python 3.3 compatable version
-
-* `STM`_ (software transactional memory): We have release a first working version, and
-continue to try out new promising paths of acheiving a fast multithreaded python
-
-* `NumPy`_ which requires installation of our fork of upstream numpy, available `on bitbucket`_
-
-.. _`Py3k`: http://pypy.org/py3donate.html
-.. _`STM`: http://pypy.org/tmdonate2.html
-.. _`NumPy`: http://pypy.org/numpydonate.html
-.. _`on bitbucket`: https://www.bitbucket.org/pypy/numpy   
-
-What is PyPy?
-=============
-
-PyPy is a very compliant Python interpreter, almost a drop-in replacement for
-CPython 2.7. It's fast (`pypy 2.3 and cpython 2.7.x`_ performance comparison;
-note that cpython's speed has not changed since 2.7.2)
-due to its integrated tracing JIT compiler.
-
-This release supports x86 machines running Linux 32/64, Mac OS X 64, Windows,
-and OpenBSD,
-as well as newer ARM hardware (ARMv6 or ARMv7, with VFPv3) running Linux. 
-
-While we support 32 bit python on Windows, work on the native Windows 64
-bit python is still stalling, we would welcome a volunteer
-to `handle that`_.
-
-.. _`pypy 2.3 and cpython 2.7.x`: http://speed.pypy.org
-.. _`handle that`: http://doc.pypy.org/en/latest/windows.html#what-is-missing-for-a-full-64-bit-translation
-
-Highlights
-==========
-
-Benchmarks improved after internal improvements in string and bytearray handling,
-and a major rewrite of the GIL handling. Many of these improvements are offshoots
-of the STM work.
-
-We merged in Python's 2.7.8 stdlib in a record time of one week, proving the
-maturity of our underlying RPython code base and PyPy interpreter.
-
-We welcomed more than 12 new contributors, and conducted two Google Summer of Code
-projects XXX details?
-
-Issues reported with our previous release were fixed after reports from users on
-our new issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at
-#pypy. Here is a summary of the user-facing changes;
-for more information see `whats-new`_:
-
-* Reduced internal copying of bytearray operations
-
-* Tweak the internal structure of StringBuilder to speed up large string
-handling, which becomes advantageous on large programs at the cost of slightly
-slower small *benchmark* type programs.
-
-* Boost performance of thread-local variables in both unjitted and jitted code
-
-* Move to a mixed polling and mutex GIL model that make mutli-threaded jitted
-  code run *much* faster
-
-* Optimize errno handling in linux
-
-* Remove ctypes pythonapi and ctypes.PyDLL, which never worked on PyPy
-
-* Fix performance regression on ufunc(<scalar>, <scalar>) in numpy
-
-* Classes in the ast module are now distinct from structures used by the compiler,
-  which simplifies and speeds up translation of our source code to the PyPy binary
-  interpreter
-
-* Upgrade stdlib from 2.7.5 to 2.7.8
-
-* 
-
-* Many issues were resolved_ since the 2.3.1 release on June 8
-
-.. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.3.1.html
-.. _resolved: https://bitbucket.org/pypy/pypy/issues?status=resolved
-
-Please try it out and let us know what you think. We especially welcome
-success stories, we know you are using PyPy, please tell us about it!
-
-Cheers
-
-The PyPy Team
-
diff --git a/pypy/doc/whatsnew-2.4.0.rst b/pypy/doc/whatsnew-2.4.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/whatsnew-2.4.0.rst
@@ -0,0 +1,66 @@
+=======================
+What's new in PyPy 2.4+
+=======================
+
+.. this is a revision shortly after release-2.3.x
+.. startrev: ca9b7cf02cf4
+
+.. branch: fix-bytearray-complexity
+Bytearray operations no longer copy the bytearray unnecessarily
+
+Added support for ``__getitem__``, ``__setitem__``, ``__getslice__``,
+``__setslice__``,  and ``__len__`` to RPython
+
+.. branch: stringbuilder2-perf
+Give the StringBuilder a more flexible internal structure, with a
+chained list of strings instead of just one string. This make it
+more efficient when building large strings, e.g. with cStringIO().
+
+Also, use systematically jit.conditional_call() instead of regular
+branches. This lets the JIT make more linear code, at the cost of
+forcing a bit more data (to be passed as arguments to
+conditional_calls). I would expect the net result to be a slight
+slow-down on some simple benchmarks and a speed-up on bigger
+programs.
+
+.. branch: ec-threadlocal
+Change the executioncontext's lookup to be done by reading a thread-
+local variable (which is implemented in C using '__thread' if
+possible, and pthread_getspecific() otherwise). On Linux x86 and
+x86-64, the JIT backend has a special optimization that lets it emit
+directly a single MOV from a %gs- or %fs-based address. It seems
+actually to give a good boost in performance.
+
+.. branch: fast-gil
+A faster way to handle the GIL, particularly in JIT code. The GIL is
+now a composite of two concepts: a global number (it's just set from
+1 to 0 and back around CALL_RELEASE_GIL), and a real mutex. If there
+are threads waiting to acquire the GIL, one of them is actively
+checking the global number every 0.1 ms to 1 ms.  Overall, JIT loops
+full of external function calls now run a bit faster (if no thread was
+started yet), or a *lot* faster (if threads were started already).
+
+.. branch: jit-get-errno
+Optimize the errno handling in the JIT, notably around external
+function calls. Linux-only.
+
+.. branch: disable_pythonapi
+Remove non-functioning ctypes.pyhonapi and ctypes.PyDLL, document this
+incompatibility with cpython. Recast sys.dllhandle to an int.
+
+.. branch: scalar-operations
+Fix performance regression on ufunc(<scalar>, <scalar>) in numpy.
+
+.. branch: pytest-25
+Update our copies of py.test and pylib to versions 2.5.2 and 1.4.20, 
+respectively.
+
+.. branch: split-ast-classes
+Classes in the ast module are now distinct from structures used by the compiler.
+
+.. branch: stdlib-2.7.8
+Upgrades from 2.7.6 to 2.7.8
+
+.. branch: cpybug-seq-radd-rmul
+Fix issue #1861 - cpython compatability madness
+
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
@@ -1,62 +1,8 @@
+
 =======================
-What's new in PyPy 2.4+
+What's new in PyPy 2.5+
 =======================
 
-.. this is a revision shortly after release-2.3.x
-.. startrev: ca9b7cf02cf4
+.. this is a revision shortly after release-2.4.x
+.. startrev: 7026746cbb1b
 
-.. branch: fix-bytearray-complexity
-Bytearray operations no longer copy the bytearray unnecessarily
-
-Added support for ``__getitem__``, ``__setitem__``, ``__getslice__``,
-``__setslice__``,  and ``__len__`` to RPython
-
-.. branch: stringbuilder2-perf
-Give the StringBuilder a more flexible internal structure, with a
-chained list of strings instead of just one string. This make it
-more efficient when building large strings, e.g. with cStringIO().
-
-Also, use systematically jit.conditional_call() instead of regular
-branches. This lets the JIT make more linear code, at the cost of
-forcing a bit more data (to be passed as arguments to
-conditional_calls). I would expect the net result to be a slight
-slow-down on some simple benchmarks and a speed-up on bigger
-programs.
-
-.. branch: ec-threadlocal
-Change the executioncontext's lookup to be done by reading a thread-
-local variable (which is implemented in C using '__thread' if
-possible, and pthread_getspecific() otherwise). On Linux x86 and
-x86-64, the JIT backend has a special optimization that lets it emit
-directly a single MOV from a %gs- or %fs-based address. It seems
-actually to give a good boost in performance.
-
-.. branch: fast-gil
-A faster way to handle the GIL, particularly in JIT code. The GIL is
-now a composite of two concepts: a global number (it's just set from
-1 to 0 and back around CALL_RELEASE_GIL), and a real mutex. If there
-are threads waiting to acquire the GIL, one of them is actively
-checking the global number every 0.1 ms to 1 ms.  Overall, JIT loops
-full of external function calls now run a bit faster (if no thread was
-started yet), or a *lot* faster (if threads were started already).
-
-.. branch: jit-get-errno
-Optimize the errno handling in the JIT, notably around external
-function calls. Linux-only.
-
-.. branch: disable_pythonapi
-Remove non-functioning ctypes.pyhonapi and ctypes.PyDLL, document this
-incompatibility with cpython. Recast sys.dllhandle to an int.
-
-.. branch: scalar-operations
-Fix performance regression on ufunc(<scalar>, <scalar>) in numpy.
-
-.. branch: pytest-25
-Update our copies of py.test and pylib to versions 2.5.2 and 1.4.20, 
-respectively.
-
-.. branch: split-ast-classes
-Classes in the ast module are now distinct from structures used by the compiler.
-
-.. branch: stdlib-2.7.8
-Upgrades from 2.7.6 to 2.7.8
diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py
--- a/pypy/interpreter/module.py
+++ b/pypy/interpreter/module.py
@@ -29,6 +29,17 @@
                           space.w_None)
         self.startup_called = False
 
+    def _cleanup_(self):
+        """Called by the annotator on prebuilt Module instances.
+        We don't have many such modules, but for the ones that
+        show up, remove their __file__ rather than translate it
+        statically inside the executable."""
+        try:
+            space = self.space
+            space.delitem(self.w_dict, space.wrap('__file__'))
+        except OperationError:
+            pass
+
     def install(self):
         """NOT_RPYTHON: installs this module into space.builtin_modules"""
         w_mod = self.space.wrap(self)
diff --git a/pypy/interpreter/test/test_app_main.py b/pypy/interpreter/test/test_app_main.py
--- a/pypy/interpreter/test/test_app_main.py
+++ b/pypy/interpreter/test/test_app_main.py
@@ -985,6 +985,11 @@
             assert sys.path == old_sys_path + [self.goal_dir]
 
             app_main.setup_bootstrap_path(self.fake_exe)
+            assert sys.executable == ''      # not executable!
+            assert sys.path == old_sys_path + [self.goal_dir]
+
+            os.chmod(self.fake_exe, 0755)
+            app_main.setup_bootstrap_path(self.fake_exe)
             assert sys.executable == self.fake_exe
             assert self.goal_dir not in sys.path
 
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
@@ -1,4 +1,5 @@
-
+import py
+from pypy.interpreter.error import OperationError
 from pypy.interpreter.module import Module
 
 class TestModule: 
@@ -17,6 +18,18 @@
         space.raises_w(space.w_AttributeError,
                        space.delattr, w_m, w('x'))
 
+    def test___file__(self, space):
+        w = space.wrap
+        m = Module(space, space.wrap('m'))
+        py.test.raises(OperationError, space.getattr, w(m), w('__file__'))
+        m._cleanup_()
+        py.test.raises(OperationError, space.getattr, w(m), w('__file__'))
+        space.setattr(w(m), w('__file__'), w('m.py'))
+        space.getattr(w(m), w('__file__'))   # does not raise
+        m._cleanup_()
+        py.test.raises(OperationError, space.getattr, w(m), w('__file__'))
+
+
 class AppTest_ModuleObject: 
     def test_attr(self):
         m = __import__('__builtin__')
diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py
--- a/pypy/module/_io/interp_stringio.py
+++ b/pypy/module/_io/interp_stringio.py
@@ -86,7 +86,7 @@
         initval = space.unicode_w(w_initval)
         size = len(initval)
         self.resize_buffer(size)
-        self.buf = [c for c in initval]
+        self.buf = list(initval)
         pos = space.getindex_w(w_pos, space.w_TypeError)
         if pos < 0:
             raise OperationError(space.w_ValueError,
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -759,17 +759,25 @@
 
         # socket's timeout is in seconds, poll's timeout in ms
         timeout = int(sock_timeout * 1000 + 0.5)
-        ready = rpoll.poll(fddict, timeout)
+        try:
+            ready = rpoll.poll(fddict, timeout)
+        except rpoll.PollError, e:
+            message = e.get_msg()
+            raise ssl_error(space, message, e.errno)
     else:
         if MAX_FD_SIZE is not None and sock_fd >= MAX_FD_SIZE:
             return SOCKET_TOO_LARGE_FOR_SELECT
 
-        if writing:
-            r, w, e = rpoll.select([], [sock_fd], [], sock_timeout)
-            ready = w
-        else:
-            r, w, e = rpoll.select([sock_fd], [], [], sock_timeout)
-            ready = r
+        try:
+            if writing:
+                r, w, e = rpoll.select([], [sock_fd], [], sock_timeout)
+                ready = w
+            else:
+                r, w, e = rpoll.select([sock_fd], [], [], sock_timeout)
+                ready = r
+        except SelectError, e:
+            message = e.get_msg()
+            raise ssl_error(space, message, e.errno)
     if ready:
         return SOCKET_OPERATION_OK
     else:
diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h
--- a/pypy/module/cpyext/include/patchlevel.h
+++ b/pypy/module/cpyext/include/patchlevel.h
@@ -29,7 +29,7 @@
 #define PY_VERSION		"2.7.8"
 
 /* PyPy version as a string */
-#define PYPY_VERSION "2.4.0-alpha0"
+#define PYPY_VERSION "2.5.0-alpha0"
 
 /* Subversion Revision number of this file (not of the repository).
  * Empty since Mercurial migration. */
diff --git a/pypy/module/pypyjit/test_pypy_c/test_cprofile.py b/pypy/module/pypyjit/test_pypy_c/test_cprofile.py
--- a/pypy/module/pypyjit/test_pypy_c/test_cprofile.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_cprofile.py
@@ -1,4 +1,4 @@
-import py, sys
+import py, sys, re
 from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
 
 class TestCProfile(BaseTestPyPyC):
@@ -28,8 +28,18 @@
             print loop.ops_by_id(method)
             # on 32-bit, there is f1=call(read_timestamp); ...;
             # f2=call(read_timestamp); f3=call(llong_sub,f1,f2)
-            # but all calls can be special-cased by the backend if supported
-            if sys.maxint != 2147483647:
-                assert ' call(' not in repr(loop.ops_by_id(method))
+            # but all calls can be special-cased by the backend if
+            # supported.  On 64-bit there is only the two calls to
+            # read_timestamp.
+            r = re.compile(r" call[(]ConstClass[(](.+?)[)]")
+            calls = r.findall(repr(loop.ops_by_id(method)))
+            if sys.maxint == 2147483647:
+                assert len(calls) == 6
+            else:
+                assert len(calls) == 2
+            for x in calls:
+                assert ('ll_read_timestamp' in x or 'llong_sub' in x
+                        or 'llong_add' in x)
+            #
             assert ' call_may_force(' not in repr(loop.ops_by_id(method))
             assert ' cond_call(' in repr(loop.ops_by_id(method))
diff --git a/pypy/module/sys/state.py b/pypy/module/sys/state.py
--- a/pypy/module/sys/state.py
+++ b/pypy/module/sys/state.py
@@ -7,15 +7,15 @@
 # ____________________________________________________________
 #
 
-class State: 
-    def __init__(self, space): 
-        self.space = space 
+class State:
+    def __init__(self, space):
+        self.space = space
 
         self.w_modules = space.newdict(module=True)
-
         self.w_warnoptions = space.newlist([])
         self.w_argv = space.newlist([])
-        self.setinitialpath(space) 
+
+        self.setinitialpath(space)
 
     def setinitialpath(self, space):
         from pypy.module.sys.initpath import compute_stdlib_path
@@ -25,10 +25,10 @@
         path = compute_stdlib_path(self, srcdir)
         self.w_path = space.newlist([space.wrap(p) for p in path])
 
-
 def get(space):
     return space.fromcache(State)
 
+
 class IOState:
     def __init__(self, space):
         from pypy.module._file.interp_file import W_File
@@ -36,17 +36,17 @@
 
         stdin = W_File(space)
         stdin.file_fdopen(0, "r", 1)
-        stdin.name = '<stdin>'
+        stdin.w_name = space.wrap('<stdin>')
         self.w_stdin = space.wrap(stdin)
 
         stdout = W_File(space)
         stdout.file_fdopen(1, "w", 1)
-        stdout.name = '<stdout>'
+        stdout.w_name = space.wrap('<stdout>')
         self.w_stdout = space.wrap(stdout)
 
         stderr = W_File(space)
         stderr.file_fdopen(2, "w", 0)
-        stderr.name = '<stderr>'
+        stderr.w_name = space.wrap('<stderr>')
         self.w_stderr = space.wrap(stderr)
 
         stdin._when_reading_first_flush(stdout)
@@ -54,9 +54,9 @@
 def getio(space):
     return space.fromcache(IOState)
 
+
 def pypy_getudir(space):
     """NOT_RPYTHON
     (should be removed from interpleveldefs before translation)"""
     from rpython.tool.udir import udir
     return space.wrap(str(udir))
-
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
@@ -91,6 +91,10 @@
         assert isinstance(sys.__stderr__, file)
         assert isinstance(sys.__stdin__, file)
 
+        assert sys.__stdin__.name == "<stdin>"
+        assert sys.__stdout__.name == "<stdout>"
+        assert sys.__stderr__.name == "<stderr>"
+
         if self.appdirect and not isinstance(sys.stdin, file):
             return
 
diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py
--- a/pypy/module/sys/version.py
+++ b/pypy/module/sys/version.py
@@ -10,7 +10,7 @@
 #XXX # sync CPYTHON_VERSION with patchlevel.h, package.py
 CPYTHON_API_VERSION        = 1013   #XXX # sync with include/modsupport.h
 
-PYPY_VERSION               = (2, 4, 0, "alpha", 0)    #XXX # sync patchlevel.h
+PYPY_VERSION               = (2, 5, 0, "alpha", 0)    #XXX # sync patchlevel.h
 
 if platform.name == 'msvc':
     COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600)
diff --git a/pypy/module/thread/test/test_thread.py b/pypy/module/thread/test/test_thread.py
--- a/pypy/module/thread/test/test_thread.py
+++ b/pypy/module/thread/test/test_thread.py
@@ -13,18 +13,26 @@
         def f():
             lock.acquire()
             lock.release()
+        start = thread._count()
         try:
             try:
                 for i in range(1000):
                     thread.start_new_thread(f, ())
             finally:
                 lock.release()
-                # wait a bit to allow most threads to finish now
-                time.sleep(0.5)
         except (thread.error, MemoryError):
             cls.w_can_start_many_threads = space.wrap(False)
         else:
             cls.w_can_start_many_threads = space.wrap(True)
+        # wait a bit to allow all threads to finish now
+        remaining = thread._count()
+        retries = 0
+        while remaining > start:
+            retries += 1
+            if retries == 200:
+                raise Exception("the test's threads don't stop!")
+            time.sleep(0.2)
+            remaining = thread._count()
 
     def test_start_new_thread(self):
         import thread
@@ -227,7 +235,7 @@
         import signal
 
         def f():
-            for x in range(5):
+            for x in range(40):
                 if waiting:
                     thread.interrupt_main()
                     return
@@ -236,7 +244,7 @@
 
         def busy_wait():
             waiting.append(None)
-            for x in range(10):
+            for x in range(50):
                 print 'tick...', x  # <-force the GIL to be released, as
                 time.sleep(0.1)    #   time.sleep doesn't do non-translated
             waiting.pop()
@@ -245,6 +253,8 @@
         signal.signal(signal.SIGINT, signal.default_int_handler)
 
         for i in range(100):
+            print
+            print "loop", i
             waiting = []
             thread.start_new_thread(f, ())
             raises(KeyboardInterrupt, busy_wait)
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -671,6 +671,7 @@
     left, right = specialnames
     errormsg = "unsupported operand type(s) for %s: '%%N' and '%%N'" % (
         symbol.replace('%', '%%'),)
+    seq_bug_compat = (symbol == '+' or symbol == '*')
 
     def binop_impl(space, w_obj1, w_obj2):
         w_typ1 = space.type(w_obj1)
@@ -686,20 +687,16 @@
             # __xxx__ and __rxxx__ methods where found by identity.
             # Note that space.is_w() is potentially not happy if one of them
             # is None...
-            if w_left_src is not w_right_src:    # XXX
-                # -- cpython bug compatibility: see objspace/std/test/
-                # -- test_unicodeobject.test_str_unicode_concat_overrides.
-                # -- The following handles "unicode + string subclass" by
-                # -- pretending that the unicode is a superclass of the
-                # -- string, thus giving priority to the string subclass'
-                # -- __radd__() method.  The case "string + unicode subclass"
-                # -- is handled directly by add__String_Unicode().
-                if symbol == '+' and space.is_w(w_typ1, space.w_unicode):
-                    w_typ1 = space.w_basestring
-                # -- end of bug compatibility
-                if space.is_true(space.issubtype(w_typ2, w_typ1)):
-                    if (w_left_src and w_right_src and
-                        not space.abstract_issubclass_w(w_left_src, w_right_src) and
+            if w_right_src and (w_left_src is not w_right_src) and w_left_src:
+                # 'seq_bug_compat' is for cpython bug-to-bug compatibility:
+                # see objspace/std/test/test_unicodeobject.*concat_overrides
+                # and objspace/test/test_descrobject.*rmul_overrides.
+                # For cases like "unicode + string subclass".
+                if ((seq_bug_compat and w_typ1.flag_sequence_bug_compat
+                                    and not w_typ2.flag_sequence_bug_compat)
+                        # the non-bug-compat part is the following check:
+                        or space.is_true(space.issubtype(w_typ2, w_typ1))):
+                    if (not space.abstract_issubclass_w(w_left_src, w_right_src) and
                         not space.abstract_issubclass_w(w_typ1, w_right_src)):
                         w_obj1, w_obj2 = w_obj2, w_obj1
                         w_left_impl, w_right_impl = w_right_impl, w_left_impl
diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -534,7 +534,7 @@
         if not e.match(space, space.w_TypeError):
             raise
     else:
-        return [c for c in buf.as_str()]
+        return list(buf.as_str())
 
     # sequence of bytes
     w_iter = space.iter(w_source)
@@ -1131,6 +1131,7 @@
     reverse = interp2app(W_BytearrayObject.descr_reverse,
                          doc=BytearrayDocstrings.reverse.__doc__),
 )
+W_BytearrayObject.typedef.flag_sequence_bug_compat = True
 
 init_signature = Signature(['source', 'encoding', 'errors'], None, None)
 init_defaults = [None, None, None]
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
@@ -951,6 +951,7 @@
     _formatter_field_name_split =
         interp2app(W_BytesObject.descr_formatter_field_name_split),
 )
+W_BytesObject.typedef.flag_sequence_bug_compat = True
 
 
 def string_escape_encode(s, quote):
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
@@ -1874,3 +1874,4 @@
     insert = interp2app(W_ListObject.descr_insert),
     remove = interp2app(W_ListObject.descr_remove),
 )
+W_ListObject.typedef.flag_sequence_bug_compat = True
diff --git a/pypy/objspace/std/stdtypedef.py b/pypy/objspace/std/stdtypedef.py
--- a/pypy/objspace/std/stdtypedef.py
+++ b/pypy/objspace/std/stdtypedef.py
@@ -93,6 +93,8 @@
                               overridetypedef=overridetypedef)
         if typedef is not overridetypedef:
             w_type.w_doc = space.wrap(typedef.doc)
+        if hasattr(typedef, 'flag_sequence_bug_compat'):
+            w_type.flag_sequence_bug_compat = typedef.flag_sequence_bug_compat
         w_type.lazyloaders = lazyloaders
         return w_type
 
diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py
--- a/pypy/objspace/std/tupleobject.py
+++ b/pypy/objspace/std/tupleobject.py
@@ -244,6 +244,7 @@
     count = interp2app(W_AbstractTupleObject.descr_count),
     index = interp2app(W_AbstractTupleObject.descr_index)
 )
+W_AbstractTupleObject.typedef.flag_sequence_bug_compat = True
 
 
 class W_TupleObject(W_AbstractTupleObject):
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
@@ -67,6 +67,7 @@
     _immutable_fields_ = ["flag_heaptype",
                           "flag_cpytype",
                           "flag_abstract?",
+                          "flag_sequence_bug_compat",
                           'needsdel',
                           'weakrefable',
                           'hasdict',
@@ -104,6 +105,7 @@
         w_self.flag_heaptype = False
         w_self.flag_cpytype = False
         w_self.flag_abstract = False
+        w_self.flag_sequence_bug_compat = False
         w_self.instancetypedef = overridetypedef
 
         if overridetypedef is not None:
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
@@ -1068,6 +1068,7 @@
     _formatter_field_name_split =
         interp2app(W_UnicodeObject.descr_formatter_field_name_split),
 )
+W_UnicodeObject.typedef.flag_sequence_bug_compat = True
 
 
 def _create_list_from_unicode(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
@@ -734,6 +734,44 @@
 
         assert X() == 'hello'
 
+    def test_sequence_rmul_overrides(self):
+        class oops(object):
+            def __rmul__(self, other):
+                return 42
+            def __index__(self):
+                return 3
+        assert '2' * oops() == 42
+        assert [2] * oops() == 42
+        assert (2,) * oops() == 42
+        assert u'2' * oops() == 42
+        assert bytearray('2') * oops() == 42
+        assert 1000 * oops() == 42
+        assert '2'.__mul__(oops()) == '222'
+
+    def test_sequence_rmul_overrides_oldstyle(self):
+        class oops:
+            def __rmul__(self, other):
+                return 42
+            def __index__(self):
+                return 3
+        assert '2' * oops() == 42
+        assert [2] * oops() == 42
+        assert (2,) * oops() == 42
+        assert u'2' * oops() == 42
+        assert bytearray('2') * oops() == 42
+        assert 1000 * oops() == 42
+        assert '2'.__mul__(oops()) == '222'
+
+    def test_sequence_radd_overrides(self):
+        class A1(list):
+            pass
+        class A2(list):
+            def __radd__(self, other):
+                return 42
+        assert [2] + A1([3]) == [2, 3]
+        assert type([2] + A1([3])) is list
+        assert [2] + A2([3]) == 42
+
 
 class AppTestWithBuiltinShortcut(AppTest_Descroperation):
     spaceconfig = {'objspace.std.builtinshortcut': True}
diff --git a/rpython/annotator/builtin.py b/rpython/annotator/builtin.py
--- a/rpython/annotator/builtin.py
+++ b/rpython/annotator/builtin.py
@@ -255,8 +255,13 @@
         BUILTIN_ANALYZERS[original] = value
 
 
- at analyzer_for(getattr(OSError.__init__, 'im_func', OSError.__init__))
-def OSError_init(s_self, *args):
+ at analyzer_for(getattr(object.__init__, 'im_func', object.__init__))
+def object_init(s_self, *args):
+    # ignore - mostly used for abstract classes initialization
+    pass
+
+ at analyzer_for(getattr(EnvironmentError.__init__, 'im_func', EnvironmentError.__init__))
+def EnvironmentError_init(s_self, *args):
     pass
 
 try:
@@ -268,11 +273,6 @@
     def WindowsError_init(s_self, *args):
         pass
 
- at analyzer_for(getattr(object.__init__, 'im_func', object.__init__))
-def object_init(s_self, *args):
-    # ignore - mostly used for abstract classes initialization
-    pass
-
 
 @analyzer_for(sys.getdefaultencoding)
 def conf():
diff --git a/rpython/annotator/classdef.py b/rpython/annotator/classdef.py
--- a/rpython/annotator/classdef.py
+++ b/rpython/annotator/classdef.py
@@ -438,8 +438,10 @@
 # ____________________________________________________________
 
 FORCE_ATTRIBUTES_INTO_CLASSES = {
-    OSError: {'errno': SomeInteger()},
-    }
+    EnvironmentError: {'errno': SomeInteger(),
+                       'strerror': SomeString(can_be_None=True),
+                       'filename': SomeString(can_be_None=True)},
+}
 
 try:
     WindowsError
@@ -455,4 +457,3 @@
 else:
     FORCE_ATTRIBUTES_INTO_CLASSES[termios.error] = \
         {'args': SomeTuple([SomeInteger(), SomeString()])}
-
diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -304,10 +304,10 @@
     def hint(self, *args_s):
         hints = args_s[-1].const
         if 'maxlength' in hints:
-            # only for iteration over lists or dicts at the moment,
+            # only for iteration over lists or dicts or strs at the moment,
             # not over an iterator object (because it has no known length)
             s_iterable = args_s[0]
-            if isinstance(s_iterable, (SomeList, SomeDict)):
+            if isinstance(s_iterable, (SomeList, SomeDict, SomeString)):
                 self = SomeList(self.listdef) # create a fresh copy
                 self.listdef.resize()
                 self.listdef.listitem.hint_maxlength = True
diff --git a/rpython/jit/backend/arm/codebuilder.py b/rpython/jit/backend/arm/codebuilder.py
--- a/rpython/jit/backend/arm/codebuilder.py
+++ b/rpython/jit/backend/arm/codebuilder.py
@@ -333,8 +333,11 @@
                     | (rn & 0xF) << 16)
 
     def DMB(self):
-        # note: 'cond' is only permitted on Thumb here
-        self.write32(0xf57ff05f)
+        # note: 'cond' is only permitted on Thumb here, but don't
+        # write literally 0xf57ff05f, because it's larger than 31 bits
+        c = cond.AL
+        self.write32(c << 28
+                    | 0x157ff05f)
 
     DIV = binary_helper_call('int_div')
     MOD = binary_helper_call('int_mod')
diff --git a/rpython/jit/backend/arm/detect.py b/rpython/jit/backend/arm/detect.py
--- a/rpython/jit/backend/arm/detect.py
+++ b/rpython/jit/backend/arm/detect.py
@@ -38,9 +38,9 @@
     try:
         buf = os.read(fd, 2048)
         if not buf:
+            n = 6  # we assume ARMv6 as base case
             debug_print("Could not detect ARM architecture "
                         "version, assuming", "ARMv%d" % n)
-            n = 6  # we asume ARMv6 as base case
     finally:
         os.close(fd)
     # "Processor       : ARMv%d-compatible processor rev 7 (v6l)"
diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -1128,6 +1128,8 @@
         self.mc.VCVT_int_to_float(res.value, r.svfp_ip.value)
         return fcond
 
+    # the following five instructions are only ARMv7;
+    # regalloc.py won't call them at all on ARMv6
     emit_op_llong_add = gen_emit_float_op('llong_add', 'VADD_i64')
     emit_op_llong_sub = gen_emit_float_op('llong_sub', 'VSUB_i64')
     emit_op_llong_and = gen_emit_float_op('llong_and', 'VAND_i64')
diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -184,7 +184,7 @@
 
 class Regalloc(BaseRegalloc):
 
-    def __init__(self, assembler=None):
+    def __init__(self, assembler):
         self.cpu = assembler.cpu
         self.assembler = assembler
         self.frame_manager = None
@@ -290,7 +290,7 @@
             return self.vfprm.convert_to_imm(value)
 
     def _prepare(self, inputargs, operations, allgcrefs):
-        cpu = self.assembler.cpu
+        cpu = self.cpu
         self.fm = ARMFrameManager(cpu.get_baseofs_of_frame_field())
         self.frame_manager = self.fm
         operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations,
@@ -550,18 +550,19 @@
                             EffectInfo.OS_LLONG_AND,
                             EffectInfo.OS_LLONG_OR,
                             EffectInfo.OS_LLONG_XOR):
-                args = self._prepare_llong_binop_xx(op, fcond)
-                self.perform_llong(op, args, fcond)
-                return
-            if oopspecindex == EffectInfo.OS_LLONG_TO_INT:
+                if self.cpu.cpuinfo.arch_version >= 7:
+                    args = self._prepare_llong_binop_xx(op, fcond)
+                    self.perform_llong(op, args, fcond)
+                    return
+            elif oopspecindex == EffectInfo.OS_LLONG_TO_INT:
                 args = self._prepare_llong_to_int(op, fcond)
                 self.perform_llong(op, args, fcond)
                 return
-            if oopspecindex == EffectInfo.OS_MATH_SQRT:
+            elif oopspecindex == EffectInfo.OS_MATH_SQRT:
                 args = self.prepare_op_math_sqrt(op, fcond)
                 self.perform_math(op, args, fcond)
                 return
-            #if oopspecindex == EffectInfo.OS_MATH_READ_TIMESTAMP:
+            #elif oopspecindex == EffectInfo.OS_MATH_READ_TIMESTAMP:
             #    ...
         return self._prepare_call(op)
 
@@ -590,7 +591,7 @@
         # spill variables that need to be saved around calls
         self.vfprm.before_call(save_all_regs=save_all_regs)
         if not save_all_regs:
-            gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap
+            gcrootmap = self.cpu.gc_ll_descr.gcrootmap
             if gcrootmap and gcrootmap.is_shadow_stack:
                 save_all_regs = 2
         self.rm.before_call(save_all_regs=save_all_regs)
@@ -1082,7 +1083,7 @@
         gcmap = self.get_gcmap([r.r0, r.r1])
         self.possibly_free_var(t)
         #
-        gc_ll_descr = self.assembler.cpu.gc_ll_descr
+        gc_ll_descr = self.cpu.gc_ll_descr
         self.assembler.malloc_cond_varsize_frame(
             gc_ll_descr.get_nursery_free_addr(),
             gc_ll_descr.get_nursery_top_addr(),
@@ -1092,7 +1093,7 @@
         self.assembler._alignment_check()
 
     def prepare_op_call_malloc_nursery_varsize(self, op, fcond):
-        gc_ll_descr = self.assembler.cpu.gc_ll_descr
+        gc_ll_descr = self.cpu.gc_ll_descr
         if not hasattr(gc_ll_descr, 'max_size_of_young_obj'):
             raise Exception("unreachable code")
             # for boehm, this function should never be called
diff --git a/rpython/jit/metainterp/warmstate.py b/rpython/jit/metainterp/warmstate.py
--- a/rpython/jit/metainterp/warmstate.py
+++ b/rpython/jit/metainterp/warmstate.py
@@ -127,6 +127,7 @@
 JC_TRACING         = 0x01
 JC_DONT_TRACE_HERE = 0x02
 JC_TEMPORARY       = 0x04
+JC_TRACING_OCCURRED= 0x08
 
 class BaseJitCell(object):
     """Subclasses of BaseJitCell are used in tandem with the single
@@ -160,6 +161,8 @@
         JC_TRACING: we are now tracing the loop from this greenkey.
         We'll likely end up with a wref_procedure_token, soonish.
 
+        JC_TRACING_OCCURRED: set if JC_TRACING was set at least once.
+
         JC_TEMPORARY: a "temporary" wref_procedure_token.
         It's the procedure_token of a dummy loop that simply calls
         back the interpreter.  Used for a CALL_ASSEMBLER where the
@@ -206,7 +209,7 @@
             # if we have this flag, and we *had* a procedure_token but
             # we no longer have one, then remove me.  this prevents this
             # JitCell from being immortal.
-            return self.has_seen_a_procedure_token()
+            return self.has_seen_a_procedure_token()     # i.e. dead weakref
         return True   # Other JitCells can be removed.
 
 # ____________________________________________________________
@@ -374,7 +377,7 @@
             if cell is None:
                 cell = JitCell(*greenargs)
                 jitcounter.install_new_cell(hash, cell)
-            cell.flags |= JC_TRACING
+            cell.flags |= JC_TRACING | JC_TRACING_OCCURRED
             try:
                 metainterp.compile_and_run_once(jitdriver_sd, *args)
             finally:
@@ -418,9 +421,15 @@
             if procedure_token is None:
                 if cell.flags & JC_DONT_TRACE_HERE:
                     if not cell.has_seen_a_procedure_token():
-                        # we're seeing a fresh JC_DONT_TRACE_HERE with no
-                        # procedure_token.  Compile now.
-                        bound_reached(hash, cell, *args)
+                        # A JC_DONT_TRACE_HERE, i.e. a non-inlinable function.
+                        # If we never tried to trace it, try it now immediately.
+                        # Otherwise, count normally.
+                        if cell.flags & JC_TRACING_OCCURRED:
+                            tick = jitcounter.tick(hash, increment_threshold)
+                        else:
+                            tick = True
+                        if tick:
+                            bound_reached(hash, cell, *args)
                         return
                 # it was an aborted compilation, or maybe a weakref that
                 # has been freed
diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py
--- a/rpython/memory/gctransform/asmgcroot.py
+++ b/rpython/memory/gctransform/asmgcroot.py
@@ -517,6 +517,8 @@
                       "anywhere I know, bug in asmgcc")
             # fish the depth
             extra_stack_depth = (ebp_in_caller + STACK_DEPTH_OFS).signed[0]
+            ll_assert((extra_stack_depth & (rffi.sizeof(lltype.Signed) - 1))
+                       == 0, "asmgcc: misaligned extra_stack_depth")
             extra_stack_depth //= rffi.sizeof(lltype.Signed)
             self._shape_decompressor.setjitframe(extra_stack_depth)
             return
diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -38,6 +38,7 @@
 
 FILEP = rffi.COpaquePtr("FILE")
 OFF_T = config['off_t']
+
 _IONBF = config['_IONBF']
 _IOLBF = config['_IOLBF']
 _IOFBF = config['_IOFBF']
@@ -47,6 +48,11 @@
 BASE_BUF_SIZE = 4096
 BASE_LINE_SIZE = 100
 
+NEWLINE_UNKNOWN = 0
+NEWLINE_CR = 1
+NEWLINE_LF = 2
+NEWLINE_CRLF = 4
+
 
 def llexternal(*args, **kwargs):
     return rffi.llexternal(*args, compilation_info=eci, **kwargs)
@@ -63,7 +69,16 @@
 c_fclose = llexternal('fclose', [FILEP], rffi.INT)
 c_pclose = llexternal('pclose', [FILEP], rffi.INT)
 
+# Note: the following two functions are called from __del__ methods,
+# so must be 'releasegil=False'.  Otherwise, a program using both
+# threads and the RFile class cannot translate.  See c684bf704d1f
+c_fclose_in_del = llexternal('fclose', [FILEP], rffi.INT, releasegil=False)
+c_pclose_in_del = llexternal('pclose', [FILEP], rffi.INT, releasegil=False)
+_fclose2 = (c_fclose, c_fclose_in_del)
+_pclose2 = (c_pclose, c_pclose_in_del)
+
 c_getc = llexternal('getc', [FILEP], rffi.INT, macro=True)
+c_ungetc = llexternal('ungetc', [rffi.INT, FILEP], rffi.INT)
 c_fgets = llexternal('fgets', [rffi.CCHARP, rffi.INT, FILEP], rffi.CCHARP)
 c_fread = llexternal('fread', [rffi.CCHARP, rffi.SIZE_T, rffi.SIZE_T, FILEP],
                      rffi.SIZE_T)
@@ -81,11 +96,15 @@
 c_ferror = llexternal('ferror', [FILEP], rffi.INT)
 c_clearerr = llexternal('clearerr', [FILEP], lltype.Void)
 
+c_stdin = rffi.CExternVariable(FILEP, 'stdin', eci, c_type='FILE*')[0]
+c_stdout = rffi.CExternVariable(FILEP, 'stdout', eci, c_type='FILE*')[0]
+c_stderr = rffi.CExternVariable(FILEP, 'stderr', eci, c_type='FILE*')[0]
+
 
 def _error(ll_file):
     err = c_ferror(ll_file)
     c_clearerr(ll_file)
-    raise OSError(err, os.strerror(err))
+    raise IOError(err, os.strerror(err))
 
 
 def _dircheck(ll_file):
@@ -96,7 +115,7 @@
     else:
         if stat.S_ISDIR(st[0]):
             err = errno.EISDIR
-            raise OSError(err, os.strerror(err))
+            raise IOError(err, os.strerror(err))
 
 
 def _sanitize_mode(mode):
@@ -120,43 +139,41 @@
 
 
 def create_file(filename, mode="r", buffering=-1):
-    mode = _sanitize_mode(mode)
+    newmode = _sanitize_mode(mode)
     ll_name = rffi.str2charp(filename)
     try:
-        ll_mode = rffi.str2charp(mode)
+        ll_mode = rffi.str2charp(newmode)
         try:
             ll_file = c_fopen(ll_name, ll_mode)
             if not ll_file:
                 errno = rposix.get_errno()
-                raise OSError(errno, os.strerror(errno))
+                raise IOError(errno, os.strerror(errno))
         finally:
             lltype.free(ll_mode, flavor='raw')
     finally:
         lltype.free(ll_name, flavor='raw')
     _dircheck(ll_file)
-    if buffering >= 0:
-        buf = lltype.nullptr(rffi.CCHARP.TO)
-        if buffering == 0:
-            c_setvbuf(ll_file, buf, _IONBF, 0)
-        elif buffering == 1:
-            c_setvbuf(ll_file, buf, _IOLBF, BUFSIZ)
-        else:
-            c_setvbuf(ll_file, buf, _IOFBF, buffering)
-    return RFile(ll_file)
+    f = RFile(ll_file, mode)
+    f._setbufsize(buffering)
+    return f
 
 
-def create_fdopen_rfile(fd, mode="r"):
-    mode = _sanitize_mode(mode)
-    ll_mode = rffi.str2charp(mode)
+def create_fdopen_rfile(fd, mode="r", buffering=-1):
+    newmode = _sanitize_mode(mode)
+    fd = rffi.cast(rffi.INT, fd)
+    rposix.validate_fd(fd)
+    ll_mode = rffi.str2charp(newmode)
     try:
-        ll_file = c_fdopen(rffi.cast(rffi.INT, fd), ll_mode)
+        ll_file = c_fdopen(fd, ll_mode)
         if not ll_file:
             errno = rposix.get_errno()
             raise OSError(errno, os.strerror(errno))
     finally:
         lltype.free(ll_mode, flavor='raw')
     _dircheck(ll_file)
-    return RFile(ll_file)
+    f = RFile(ll_file, mode)
+    f._setbufsize(buffering)
+    return f
 
 
 def create_temp_rfile():
@@ -180,16 +197,61 @@
             lltype.free(ll_type, flavor='raw')
     finally:
         lltype.free(ll_command, flavor='raw')
-    return RFile(ll_file, c_pclose)
+    return RFile(ll_file, close2=_pclose2)
+
+
+def create_stdio():
+    close2 = (None, None)
+    stdin = RFile(c_stdin(), close2=close2)
+    stdout = RFile(c_stdout(), close2=close2)
+    stderr = RFile(c_stderr(), close2=close2)
+    return stdin, stdout, stderr
 
 
 class RFile(object):
-    def __init__(self, ll_file, do_close=c_fclose):
+    _setbuf = lltype.nullptr(rffi.CCHARP.TO)
+    _univ_newline = False
+    _newlinetypes = NEWLINE_UNKNOWN
+    _skipnextlf = False
+
+    def __init__(self, ll_file, mode=None, close2=_fclose2):
         self._ll_file = ll_file
-        self._do_close = do_close
+        if mode is not None:
+            self._univ_newline = 'U' in mode
+        self._close2 = close2
+
+    def _setbufsize(self, bufsize):
+        if bufsize >= 0:
+            if bufsize == 0:
+                mode = _IONBF
+            elif bufsize == 1:
+                mode = _IOLBF
+                bufsize = BUFSIZ
+            else:
+                mode = _IOFBF
+            if self._setbuf:
+                lltype.free(self._setbuf, flavor='raw')
+            if mode == _IONBF:
+                self._setbuf = lltype.nullptr(rffi.CCHARP.TO)
+            else:
+                self._setbuf = lltype.malloc(rffi.CCHARP.TO, bufsize, flavor='raw')
+            c_setvbuf(self._ll_file, self._setbuf, mode, bufsize)
 
     def __del__(self):
-        self.close()
+        """Closes the described file when the object's last reference
+        goes away.  Unlike an explicit call to close(), this is meant
+        as a last-resort solution and cannot release the GIL or return
+        an error code."""
+        ll_file = self._ll_file
+        if ll_file:
+            do_close = self._close2[1]
+            if do_close:
+                do_close(ll_file)       # return value ignored
+            if self._setbuf:
+                lltype.free(self._setbuf, flavor='raw')
+
+    def _cleanup_(self):
+        self._ll_file = lltype.nullptr(FILEP.TO)
 
     def close(self):
         """Closes the described file.
@@ -204,16 +266,69 @@
         if ll_file:
             # double close is allowed
             self._ll_file = lltype.nullptr(FILEP.TO)
-            res = self._do_close(ll_file)
-            if res == -1:
-                errno = rposix.get_errno()
-                raise OSError(errno, os.strerror(errno))
+            do_close = self._close2[0]
+            try:
+                if do_close:
+                    res = do_close(ll_file)
+                    if res == -1:
+                        errno = rposix.get_errno()
+                        raise IOError(errno, os.strerror(errno))
+            finally:
+                if self._setbuf:
+                    lltype.free(self._setbuf, flavor='raw')
+                    self._setbuf = lltype.nullptr(rffi.CCHARP.TO)
         return res
 
     def _check_closed(self):
         if not self._ll_file:
             raise ValueError("I/O operation on closed file")
 
+    def _fread(self, buf, n, stream):
+        if not self._univ_newline:
+            return c_fread(buf, 1, n, stream)
+
+        i = 0
+        dst = buf
+        newlinetypes = self._newlinetypes
+        skipnextlf = self._skipnextlf
+        while n:
+            nread = c_fread(dst, 1, n, stream)
+            if nread == 0:
+                break
+
+            src = dst
+            n -= nread
+            shortread = n != 0
+            while nread:
+                nread -= 1
+                c = src[0]
+                src = rffi.ptradd(src, 1)
+                if c == '\r':
+                    dst[0] = '\n'
+                    dst = rffi.ptradd(dst, 1)
+                    i += 1
+                    skipnextlf = True
+                elif skipnextlf and c == '\n':
+                    skipnextlf = False
+                    newlinetypes |= NEWLINE_CRLF
+                    n += 1
+                else:
+                    if c == '\n':
+                        newlinetypes |= NEWLINE_LF
+                    elif skipnextlf:
+                        newlinetypes |= NEWLINE_CR
+                    dst[0] = c
+                    dst = rffi.ptradd(dst, 1)
+                    i += 1
+                    skipnextlf = False
+            if shortread:
+                if skipnextlf and c_feof(stream):
+                    newlinetypes |= NEWLINE_CR
+                break
+        self._newlinetypes = newlinetypes
+        self._skipnextlf = skipnextlf
+        return i
+
     def read(self, size=-1):
         # XXX CPython uses a more delicate logic here
         self._check_closed()
@@ -226,7 +341,7 @@
             try:
                 s = StringBuilder()
                 while True:
-                    returned_size = c_fread(buf, 1, BASE_BUF_SIZE, ll_file)
+                    returned_size = self._fread(buf, BASE_BUF_SIZE, ll_file)
                     returned_size = intmask(returned_size)  # is between 0 and BASE_BUF_SIZE
                     if returned_size == 0:
                         if c_feof(ll_file):
@@ -238,12 +353,13 @@
                 lltype.free(buf, flavor='raw')
         else:  # size > 0
             with rffi.scoped_alloc_buffer(size) as buf:
-                returned_size = c_fread(buf.raw, 1, size, ll_file)
+                returned_size = self._fread(buf.raw, size, ll_file)
                 returned_size = intmask(returned_size)  # is between 0 and size
                 if returned_size == 0:
                     if not c_feof(ll_file):
                         raise _error(ll_file)
                 s = buf.str(returned_size)
+                assert s is not None
             return s
 
     def _readline1(self, raw_buf):
@@ -284,7 +400,7 @@
         self._check_closed()
         if size == 0:
             return ""
-        elif size < 0:
+        elif size < 0 and not self._univ_newline:
             with rffi.scoped_alloc_buffer(BASE_LINE_SIZE) as buf:
                 c = self._readline1(buf.raw)
                 if c >= 0:
@@ -299,19 +415,50 @@
                         break
                 s.append_charpsize(buf.raw, c)
             return s.build()
-        else:  # size > 0
+        else:  # size > 0 or self._univ_newline
             ll_file = self._ll_file
+            c = 0
             s = StringBuilder()
-            while s.getlength() < size:
-                c = c_getc(ll_file)
+            if self._univ_newline:
+                newlinetypes = self._newlinetypes
+                skipnextlf = self._skipnextlf
+                while size < 0 or s.getlength() < size:
+                    c = c_getc(ll_file)
+                    if c == EOF:
+                        break
+                    if skipnextlf:
+                        skipnextlf = False
+                        if c == ord('\n'):
+                            newlinetypes |= NEWLINE_CRLF
+                            c = c_getc(ll_file)
+                            if c == EOF:
+                                break
+                        else:
+                            newlinetypes |= NEWLINE_CR
+                    if c == ord('\r'):
+                        skipnextlf = True
+                        c = ord('\n')
+                    elif c == ord('\n'):
+                        newlinetypes |= NEWLINE_LF
+                    s.append(chr(c))
+                    if c == ord('\n'):
+                        break
                 if c == EOF:
-                    if c_ferror(ll_file):
-                        raise _error(ll_file)
-                    break
-                c = chr(c)
-                s.append(c)
-                if c == '\n':
-                    break
+                    if skipnextlf:
+                        newlinetypes |= NEWLINE_CR
+                self._newlinetypes = newlinetypes
+                self._skipnextlf = skipnextlf
+            else:
+                while s.getlength() < size:
+                    c = c_getc(ll_file)
+                    if c == EOF:
+                        break
+                    s.append(chr(c))
+                    if c == ord('\n'):
+                        break
+            if c == EOF:
+                if c_ferror(ll_file):
+                    raise _error(ll_file)
             return s.build()
 
     @enforceargs(None, str)
@@ -325,7 +472,8 @@
             bytes = c_fwrite(ll_value, 1, length, self._ll_file)
             if bytes != length:
                 errno = rposix.get_errno()
-                raise OSError(errno, os.strerror(errno))
+                c_clearerr(self._ll_file)
+                raise IOError(errno, os.strerror(errno))
         finally:
             rffi.free_nonmovingbuffer(value, ll_value)
 
@@ -334,7 +482,7 @@
         res = c_fflush(self._ll_file)
         if res != 0:
             errno = rposix.get_errno()
-            raise OSError(errno, os.strerror(errno))
+            raise IOError(errno, os.strerror(errno))
 
     def truncate(self, arg=-1):
         self._check_closed()
@@ -344,23 +492,36 @@
         res = c_ftruncate(self.fileno(), arg)
         if res == -1:
             errno = rposix.get_errno()
-            raise OSError(errno, os.strerror(errno))
+            raise IOError(errno, os.strerror(errno))
 
     def seek(self, pos, whence=0):
         self._check_closed()
         res = c_fseek(self._ll_file, pos, whence)
         if res == -1:
             errno = rposix.get_errno()
-            raise OSError(errno, os.strerror(errno))
+            raise IOError(errno, os.strerror(errno))
+        self._skipnextlf = False
 
     def tell(self):
         self._check_closed()
         res = intmask(c_ftell(self._ll_file))
         if res == -1:
             errno = rposix.get_errno()
-            raise OSError(errno, os.strerror(errno))
+            raise IOError(errno, os.strerror(errno))
+        if self._skipnextlf:
+            c = c_getc(self._ll_file)
+            if c == ord('\n'):
+                self._newlinetypes |= NEWLINE_CRLF
+                res += 1
+                self._skipnextlf = False
+            elif c != EOF:
+                c_ungetc(c, self._ll_file)
         return res
 
     def fileno(self):
         self._check_closed()
         return intmask(c_fileno(self._ll_file))
+
+    def isatty(self):
+        self._check_closed()
+        return os.isatty(c_fileno(self._ll_file))
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -119,7 +119,7 @@
         return 1
 
     def validate_fd(fd):
-        return 1
+        pass
 
 def closerange(fd_low, fd_high):
     # this behaves like os.closerange() from Python 2.6.
diff --git a/rpython/rlib/streamio.py b/rpython/rlib/streamio.py
--- a/rpython/rlib/streamio.py
+++ b/rpython/rlib/streamio.py
@@ -900,6 +900,13 @@
 
         return '\n'.join(result)
 
+    def readline(self):
+        line = self.base.readline()
+        limit = len(line) - 2
+        if limit >= 0 and line[limit] == '\r' and line[limit + 1] == '\n':
+            line = line[:limit] + '\n'
+        return line
+
     def tell(self):
         pos = self.base.tell()
         return pos - len(self.lfbuffer)
diff --git a/rpython/rlib/test/test_rfile.py b/rpython/rlib/test/test_rfile.py
--- a/rpython/rlib/test/test_rfile.py
+++ b/rpython/rlib/test/test_rfile.py
@@ -1,4 +1,4 @@
-import os, sys, py, errno
+import os, sys, py, errno, gc
 from rpython.rtyper.test.tool import BaseRtypingTest
 from rpython.tool.udir import udir
 from rpython.rlib import rfile
@@ -25,61 +25,67 @@
             f.close()
 
         f()
+        assert open(fname, "r").read() == "dupa"
         self.interpret(f, [])
         assert open(fname, "r").read() == "dupa"
 
     def test_open_errors(self):
-        def f(exc):
-            def g(run):
-                try:
-                    open('zzz', 'badmode')
-                except ValueError:
-                    pass
+        def f(run):
+            try:
+                open('zzz', 'badmode')
+            except ValueError:
+                pass
+            else:
+                assert False
+
+            try:
+                open('zzz')
+            except IOError as e:
+                assert e.errno == errno.ENOENT
+            else:
+                assert False
+
+            try:
+                open('.')
+            except IOError as e:
+                if os.name == 'posix':
+                    assert e.errno == errno.EISDIR
                 else:
-                    assert False
+                    assert e.errno == errno.EACCES
+            else:
+                assert False
 
-                try:
-                    open('zzz')
-                except exc as e:
-                    assert e.errno == errno.ENOENT
-                else:
-                    assert False
+            try:
+                os.fdopen(42, "badmode")
+            except ValueError:
+                pass
+            else:
+                assert False
 
-                try:
-                    open('.')
-                except exc as e:
-                    if os.name == 'posix':
+            try:
+                fd = os.open('.', os.O_RDONLY, 0777)
+            except OSError as e:
+                assert os.name == 'nt' and e.errno == errno.EACCES
+            else:
+                assert os.name != 'nt'
+                if run:
+                    try:
+                        os.fdopen(fd)
+                    except IOError as e:
                         assert e.errno == errno.EISDIR
                     else:
-                        assert e.errno == errno.EACCES
-                else:
-                    assert False
+                        assert False
+                os.close(fd)
 
-                try:
-                    os.fdopen(42, "badmode")
-                except ValueError:
-                    pass
-                else:
-                    assert False
+            try:
+                os.fdopen(12345)
+            except OSError as e:
+                assert e.errno == errno.EBADF
+            else:
+                assert False
 
-                try:
-                    fd = os.open('.', os.O_RDONLY, 0777)
-                except OSError as e:
-                    assert os.name == 'nt' and e.errno == errno.EACCES
-                else:
-                    assert os.name != 'nt'
-                    if run:
-                        try:
-                            os.fdopen(fd)
-                        except exc as e:
-                            assert e.errno == errno.EISDIR
-                        else:
-                            assert False
-                    os.close(fd)
-            return g
-
-        f(IOError)(sys.version_info >= (2, 7, 9))
-        self.interpret(f(OSError), [True])
+        f(sys.version_info >= (2, 7, 9))
+        self.interpret(f, [True])
 
     @py.test.mark.skipif("sys.platform == 'win32'")
     # http://msdn.microsoft.com/en-us/library/86cebhfs.aspx
@@ -98,15 +104,53 @@
         f()
         self.interpret(f, [])
 
+    @py.test.mark.skipif("sys.platform == 'win32'")
+    # http://msdn.microsoft.com/en-us/library/86cebhfs.aspx
+    def test_fdopen_buffering_line(self):
+        fname = str(self.tmpdir.join('file_1a'))
+
+        def f():
+            g = open(fname, 'w')
+            f = os.fdopen(os.dup(g.fileno()), 'w', 1)
+            g.close()
+            f.write('dupa\ndupb')
+            f2 = open(fname, 'r')
+            assert f2.read() == 'dupa\n'
+            f.close()
+            assert f2.read() == 'dupb'
+            f2.close()
+
+        f()
+        self.interpret(f, [])
+
     def test_open_buffering_full(self):
         fname = str(self.tmpdir.join('file_1b'))
 
         def f():
             f = open(fname, 'w', 128)
-            f.write('dupa')
+            f.write('dupa\ndupb')
             f2 = open(fname, 'r')
             assert f2.read() == ''
-            f.write('z' * 5000)
+            f.write('z' * 120)
+            assert f2.read() != ''
+            f.close()
+            assert f2.read() != ''
+            f2.close()
+
+        f()
+        self.interpret(f, [])
+
+    def test_fdopen_buffering_full(self):
+        fname = str(self.tmpdir.join('file_1b'))
+
+        def f():
+            g = open(fname, 'w')
+            f = os.fdopen(os.dup(g.fileno()), 'w', 128)
+            g.close()
+            f.write('dupa\ndupb')
+            f2 = open(fname, 'r')
+            assert f2.read() == ''
+            f.write('z' * 120)
             assert f2.read() != ''
             f.close()
             assert f2.read() != ''
@@ -120,10 +164,28 @@
 
         def f():
             f = open(fname, "w")
+            try:
+                f.read()
+            except IOError as e:
+                pass
+            else:
+                assert False
+            try:
+                f.readline()
+            except IOError as e:
+                pass
+            else:
+                assert False
             f.write("dupa\x00dupb")
             f.close()
             for mode in ['r', 'U']:
                 f2 = open(fname, mode)
+                try:
+                    f2.write('z')
+                except IOError as e:
+                    pass
+                else:
+                    assert False
                 dupa = f2.read(0)
                 assert dupa == ""
                 dupa = f2.read()
@@ -162,6 +224,40 @@
             assert d == "a"
             assert e == ""
 
+        f()
+        self.interpret(f, [])
+
+    def test_read_universal(self):
+        fname = str(self.tmpdir.join('read_univ'))
+        with open(fname, 'wb') as f:
+            f.write("dupa\ndupb\r\ndupc\rdupd")
+
+        def f():
+            f = open(fname, 'U')
+            assert f.read() == "dupa\ndupb\ndupc\ndupd"
+            assert f.read() == ""
+            f.seek(0)
+            assert f.read(10) == "dupa\ndupb\n"
+            assert f.read(42) == "dupc\ndupd"
+            assert f.read(1) == ""
+            f.seek(0)
+            assert f.readline() == "dupa\n"
+            assert f.tell() == 5
+            assert f.readline() == "dupb\n"
+            assert f.tell() == 11
+            assert f.readline() == "dupc\n"
+            assert f.tell() == 16
+            assert f.readline() == "dupd"
+            assert f.tell() == 20
+            assert f.readline() == ""
+            f.seek(0)
+            assert f.readline() == "dupa\n"
+            assert f.readline() == "dupb\n"
+            f.seek(4)
+            assert f.read(1) == "\n"
+            f.close()
+
+        f()
         self.interpret(f, [])
 
     def test_seek(self):
@@ -172,6 +268,12 @@
             f.write("xxx")
             f.seek(0)
             assert f.read() == "xxx"
+            try:
+                f.seek(0, 42)
+            except IOError as e:
+                assert e.errno == errno.EINVAL
+            else:
+                assert False
             f.close()
 
         f()
@@ -196,6 +298,12 @@
             new_fno = os.dup(f.fileno())
             f2 = os.fdopen(new_fno, "w")
             f.close()
+            try:
+                f2.read()
+            except IOError as e:
+                pass
+            else:
+                assert False
             f2.write("xxx")
             f2.close()
 
@@ -209,11 +317,14 @@
 
         def f():
             f = open(fname, "w")
+            assert not f.isatty()
             try:
                 return f.fileno()
             finally:
                 f.close()
 
+        res = f()
+        assert res > 2
         res = self.interpret(f, [])


More information about the pypy-commit mailing list