[pypy-commit] pypy default: merge upstream

krono noreply at buildbot.pypy.org
Wed Jul 24 18:14:03 CEST 2013


Author: Tobias Pape <tobias at netshed.de>
Branch: 
Changeset: r65619:d63e416d3f3d
Date: 2013-05-06 11:32 +0200
http://bitbucket.org/pypy/pypy/changeset/d63e416d3f3d/

Log:	merge upstream

diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py
--- a/lib_pypy/_ctypes/structure.py
+++ b/lib_pypy/_ctypes/structure.py
@@ -167,7 +167,6 @@
             return
         if '_fields_' not in self.__dict__:
             self._fields_ = []
-            self._names = []
             _set_shape(self, [], self._is_union)
 
     __setattr__ = struct_setattr
diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-2.0.0.rst
@@ -0,0 +1,61 @@
+============================
+PyPy 2.0 - Einstein Sandwich
+============================
+
+We're pleased to announce PyPy 2.0. This is a stable release that brings
+a swath of bugfixes, small performance improvements and compatibility fixes.
+
+You can download the PyPy 2.0 release here:
+
+    http://pypy.org/download.html
+
+The two biggest changes since PyPy 1.9 are:
+
+* stackless is now supported including greenlets, which means eventlet
+  and gevent should work (but read below about gevent)
+
+* PyPy now contains release 0.6 of `cffi`_ as a builtin module, which
+  is preferred way of calling C from Python that works well on PyPy
+
+.. _`cffi`: http://cffi.readthedocs.org
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 64 or
+Windows 32.  Windows 64 work is still stalling, we would welcome a volunteer
+to handle that. ARM support is on the way and we're expecting to release
+an alpha ARM version shortly.
+
+.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org
+
+Highlights
+==========
+
+* Stackless including greenlets should work. For gevent, you need to check
+  out `pypycore`_ and use the `pypy-hacks`_ branch of gevent.
+
+* cffi is now a module included with PyPy.  (`cffi`_ also exists for
+  CPython; the two versions should be fully compatible.)  It is the
+  preferred way of calling C from Python that works on PyPy.
+
+* Callbacks from C are now JITted, which means XML parsing is much faster.
+
+* A lot of speed improvements in various language corners, most of them small,
+  but speeding up some particular corners a lot.
+
+* The JIT was refactored to emit machine code which manipulates a "frame"
+  that lives on the heap rather than on the stack.  This is what makes
+  Stackless work, and it could bring another future speed-up (not done yet).
+
+* A lot of stability issues fixed.
+
+.. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/
+.. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks
+
+Cheers,
+fijal, arigo and the PyPy team
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-2.0.rst
copy from pypy/doc/whatsnew-head.rst
copy to pypy/doc/whatsnew-2.0.rst
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,140 +1,7 @@
 ======================
-What's new in PyPy 2.0
+What's new in PyPy 2.1
 ======================
 
-.. this is a revision shortly after release-2.0-beta1
-.. startrev: 0e6161a009c6
+.. this is a revision shortly after release-2.0
+.. startrev: a13c07067613
 
-.. branch: split-rpython
-Split rpython and pypy into seperate directories
-
-.. branch: callback-jit
-Callbacks from C are now better JITted
-
-.. branch: fix-jit-logs
-
-.. branch: remove-globals-in-jit
-
-.. branch: length-hint
-Implement __lenght_hint__ according to PEP 424
-
-.. branch: numpypy-longdouble
-Long double support for numpypy
-
-.. branch: numpypy-disable-longdouble
-Since r_longdouble support is missing, disable all longdouble and derivative
-dtypes using ENABLED_LONG_DOUBLE = False
-
-.. branch: numpypy-real-as-view
-Convert real, imag from ufuncs to views. This involves the beginning of
-view() functionality
-
-.. branch: indexing-by-array
-Adds indexing by scalar, adds int conversion from scalar and single element array,
-fixes compress, indexing by an array with a smaller shape and the indexed object.
-
-.. branch: str-dtype-improvement
-Allow concatenation of str and numeric arrays
-
-.. branch: signatures
-Improved RPython typing
-
-.. branch: rpython-bytearray
-Rudimentary support for bytearray in RPython
-
-.. branch: refactor-call_release_gil
-Fix a bug which caused cffi to return the wrong result when calling a C
-function which calls a Python callback which forces the frames
-
-.. branch: virtual-raw-mallocs
-JIT optimizations which make cffi calls even faster, by removing the need to
-allocate a temporary buffer where to store the arguments.
-
-.. branch: improve-docs-2
-Improve documents and straighten out links
-
-.. branch: fast-newarray
-Inline the fast path of newarray in the assembler.
-Disabled on ARM until we fix issues.
-
-.. branch: reflex-support
-Allow dynamic loading of a (Reflex) backend that implements the C-API needed
-to provide reflection information
-
-.. branches we don't care about
-.. branch: autoreds
-.. branch: kill-faking
-.. branch: improved_ebnfparse_error
-.. branch: task-decorator
-.. branch: fix-e4fa0b2
-.. branch: win32-fixes
-.. branch: numpy-unify-methods
-.. branch: fix-version-tool
-.. branch: popen2-removal
-.. branch: pickle-dumps
-.. branch: scalar_get_set
-
-.. branch: release-2.0-beta1
-
-.. branch: remove-PYPY_NOT_MAIN_FILE
-
-.. branch: missing-jit-operations
-
-.. branch: fix-lookinside-iff-oopspec
-Fixed the interaction between two internal tools for controlling the JIT.
-
-.. branch: inline-virtualref-2
-Better optimized certain types of frame accesses in the JIT, particularly
-around exceptions that escape the function they were raised in.
-
-.. branch: missing-ndarray-attributes
-Some missing attributes from ndarrays
-
-.. branch: cleanup-tests
-Consolidated the lib_pypy/pypy_test and pypy/module/test_lib_pypy tests into
-one directory for reduced confusion and so they all run nightly.
-
-.. branch: unquote-faster
-.. branch: urlparse-unquote-faster
-
-.. branch: signal-and-thread
-Add "__pypy__.thread.signals_enabled", a context manager. Can be used in a
-non-main thread to enable the processing of signal handlers in that thread.
-
-.. branch: coding-guide-update-rlib-refs
-.. branch: rlib-doc-rpython-refs
-.. branch: clean-up-remaining-pypy-rlib-refs
-
-.. branch: enumerate-rstr
-Support enumerate() over rstr types.
-
-.. branch: cleanup-numpypy-namespace
-Cleanup _numpypy and numpypy namespaces to more closely resemble numpy.
-
-.. branch: kill-flowobjspace
-Random cleanups to hide FlowObjSpace from public view.
-
-.. branch: vendor-rename
-
-.. branch: jitframe-on-heap
-Moves optimized JIT frames from stack to heap. As a side effect it enables
-stackless to work well with the JIT on PyPy. Also removes a bunch of code from
-the GC which fixes cannot find gc roots.
-
-.. branch: pycon2013-doc-fixes
-Documentation fixes after going through the docs at PyCon 2013 sprint.
-
-.. branch: extregistry-refactor
-
-.. branch: remove-list-smm
-.. branch: bridge-logging
-.. branch: curses_cffi
-cffi implementation of _curses
-
-.. branch: sqlite-cffi
-cffi implementation of sqlite3
-
-.. branch: release-2.0-beta2
-.. branch: unbreak-freebsd
-
-.. branch: virtualref-virtualizable
diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py
--- a/pypy/goal/getnightly.py
+++ b/pypy/goal/getnightly.py
@@ -6,8 +6,14 @@
 
 if sys.platform.startswith('linux'):
     arch = 'linux'
+    cmd = 'wget "%s"'
+    tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'"
+if sys.platform.startswith('darwin'):
+    arch = 'osx'
+    cmd = 'curl -O "%s"'
+    tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'"
 else:
-    print 'Cannot determine the platform, please update this scrip'
+    print 'Cannot determine the platform, please update this script'
     sys.exit(1)
 
 if sys.maxint == 2**63 - 1:
@@ -23,10 +29,9 @@
 tmp = py.path.local.mkdtemp()
 mydir = tmp.chdir()
 print 'Downloading pypy to', tmp
-if os.system('wget "%s"' % url) != 0:
+if os.system(cmd % url) != 0:
     sys.exit(1)
 
 print 'Extracting pypy binary'
 mydir.chdir()
-os.system("tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" % tmp.join(filename))
-
+os.system(tar % tmp.join(filename))
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
@@ -85,3 +85,7 @@
         from rpython.jit.backend import detect_cpu
         model = detect_cpu.autodetect_main_model_and_size()
         self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model)
+        if self.space.config.translation.jit:
+            features = detect_cpu.getcpufeatures(model)
+            self.extra_interpdef('jit_backend_features',
+                                    'space.wrap(%r)' % features)
diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py
--- a/pypy/module/__pypy__/test/test_special.py
+++ b/pypy/module/__pypy__/test/test_special.py
@@ -62,3 +62,14 @@
         assert list_strategy(l) == "empty"
         o = 5
         raises(TypeError, list_strategy, 5)
+
+
+class AppTestJitFeatures(object):
+    spaceconfig = {"translation.jit": True}
+
+    def test_jit_backend_features(self):
+        from __pypy__ import jit_backend_features
+        supported_types = jit_backend_features
+        assert isinstance(supported_types, list)
+        for x in supported_types:
+            assert x in ['floats', 'singlefloats', 'longlong']
diff --git a/pypy/module/_io/__init__.py b/pypy/module/_io/__init__.py
--- a/pypy/module/_io/__init__.py
+++ b/pypy/module/_io/__init__.py
@@ -38,5 +38,5 @@
 
     def shutdown(self, space):
         # at shutdown, flush all open streams.  Ignore I/O errors.
-        from pypy.module._io.interp_iobase import get_autoflushher
-        get_autoflushher(space).flush_all(space)
+        from pypy.module._io.interp_iobase import get_autoflusher
+        get_autoflusher(space).flush_all(space)
diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py
--- a/pypy/module/_io/interp_iobase.py
+++ b/pypy/module/_io/interp_iobase.py
@@ -47,7 +47,7 @@
         self.w_dict = space.newdict()
         self.__IOBase_closed = False
         self.streamholder = None # needed by AutoFlusher
-        get_autoflushher(space).add(self)
+        get_autoflusher(space).add(self)
 
     def getdict(self, space):
         return self.w_dict
@@ -103,7 +103,7 @@
             space.call_method(self, "flush")
         finally:
             self.__IOBase_closed = True
-            get_autoflushher(space).remove(self)
+            get_autoflusher(space).remove(self)
 
     def flush_w(self, space):
         if self._CLOSED():
@@ -363,5 +363,5 @@
                 else:
                     streamholder.autoflush(space)
 
-def get_autoflushher(space):
+def get_autoflusher(space):
     return space.fromcache(AutoFlusher)
diff --git a/pypy/module/_random/interp_random.py b/pypy/module/_random/interp_random.py
--- a/pypy/module/_random/interp_random.py
+++ b/pypy/module/_random/interp_random.py
@@ -33,8 +33,8 @@
             elif space.isinstance_w(w_n, space.w_long):
                 w_n = space.abs(w_n)
             else:
-                # XXX not perfectly like CPython
-                w_n = space.abs(space.hash(w_n))
+                n = space.hash_w(w_n)
+                w_n = space.wrap(r_uint(n))
         key = []
         w_one = space.newint(1)
         w_two = space.newint(2)
diff --git a/pypy/module/_random/test/test_random.py b/pypy/module/_random/test/test_random.py
--- a/pypy/module/_random/test/test_random.py
+++ b/pypy/module/_random/test/test_random.py
@@ -42,13 +42,14 @@
         rnd1.setstate((-1, ) * 624 + (0, ))
 
     def test_seed(self):
-        import _random
+        import _random, sys
         rnd = _random.Random()
         rnd.seed()
         different_nums = []
+        mask = sys.maxint * 2 + 1
         for obj in ["spam and eggs", 3.14, 1+2j, 'a', tuple('abc')]:
             nums = []
-            for o in [obj, hash(obj), -hash(obj)]:
+            for o in [obj, hash(obj) & mask, -(hash(obj) & mask)]:
                 rnd.seed(o)
                 nums.append([rnd.random() for i in range(100)])
             n1 = nums[0]
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -16,6 +16,8 @@
 from rpython.rlib.objectmodel import we_are_translated, specialize
 from pypy.module.sys.version import PYPY_VERSION
 
+_WIN32 = sys.platform == 'win32'
+
 SEARCH_ERROR = 0
 PY_SOURCE = 1
 PY_COMPILED = 2
@@ -27,12 +29,8 @@
 # PY_CODERESOURCE = 8
 IMP_HOOK = 9
 
-if sys.platform == 'win32':
-    SO = ".pyd"
-else:
-    SO = ".so"
+SO = '.pyd' if _WIN32 else '.so'
 DEFAULT_SOABI = 'pypy-%d%d' % PYPY_VERSION[:2]
-CHECK_FOR_PYW = sys.platform == 'win32'
 
 @specialize.memo()
 def get_so_extension(space):
@@ -64,7 +62,7 @@
         return PY_SOURCE, ".py", "U"
 
     # on Windows, also check for a .pyw file
-    if CHECK_FOR_PYW:
+    if _WIN32:
         pyfile = filepart + ".pyw"
         if file_exists(pyfile):
             return PY_SOURCE, ".pyw", "U"
diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py
--- a/pypy/module/pypyjit/test_pypy_c/test_array.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_array.py
@@ -119,6 +119,12 @@
         """)
 
     def test_array_of_floats(self):
+        try:
+            from __pypy__ import jit_backend_features
+            if 'singlefloats' not in jit_backend_features:
+                py.test.skip("test requres singlefloats support from the JIT backend")
+        except ImportError:
+            pass
         def main():
             from array import array
             img = array('f', [21.5]*1000)
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
@@ -230,6 +230,17 @@
         pt = POINT(y=2, x=1)
         assert (pt.x, pt.y) == (1, 2)
 
+    def test_subclass_initializer(self):
+        class POINT(Structure):
+            _fields_ = [("x", c_int), ("y", c_int)]
+
+        class POSITION(POINT):
+            # A subclass without _fields_
+            pass
+        pos = POSITION(1, 2)
+        assert (pos.x, pos.y) == (1, 2)
+        
+
     def test_invalid_field_types(self):
         class POINT(Structure):
             pass
@@ -538,6 +549,7 @@
         raises(AttributeError, setattr, X, "_fields_", [])
         Y.__fields__ = []
 
+
 class TestPatologicalCases(BaseCTypesTestChecker):
     def test_structure_overloading_getattr(self):
         class X(Structure):
diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -39,12 +39,10 @@
 
     def unicode_w(w_self, space):
         # Use the default encoding.
-        from pypy.objspace.std.unicodetype import unicode_from_string, \
-                decode_object
+        from pypy.objspace.std.unicodetype import (unicode_from_string,
+            decode_object, _get_encoding_and_errors)
         w_defaultencoding = space.call_function(space.sys.get(
                                                 'getdefaultencoding'))
-        from pypy.objspace.std.unicodetype import _get_encoding_and_errors, \
-            unicode_from_string, decode_object
         encoding, errors = _get_encoding_and_errors(space, w_defaultencoding,
                                                     space.w_None)
         if encoding is None and errors is None:
@@ -236,7 +234,7 @@
 def str_title__String(space, w_self):
     input = w_self._value
     builder = StringBuilder(len(input))
-    prev_letter=' '
+    prev_letter = ' '
 
     for pos in range(len(input)):
         ch = input[pos]
@@ -434,7 +432,7 @@
             space.wrap("rjust() argument 2 must be a single character"))
 
     d = u_arg - len(u_self)
-    if d>0:
+    if d > 0:
         fillchar = fillchar[0]    # annotator hint: it's a single character
         u_self = d * fillchar + u_self
 
@@ -450,7 +448,7 @@
             space.wrap("ljust() argument 2 must be a single character"))
 
     d = u_arg - len(u_self)
-    if d>0:
+    if d > 0:
         fillchar = fillchar[0]    # annotator hint: it's a single character
         u_self += d * fillchar
 
@@ -471,12 +469,12 @@
     return space.newbool(self.find(sub) >= 0)
 
 def str_find__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-    (self, start, end) =  _convert_idx_params(space, w_self, w_start, w_end)
+    (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end)
     res = self.find(w_sub._value, start, end)
     return space.wrap(res)
 
 def str_rfind__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-    (self, start, end) =  _convert_idx_params(space, w_self, w_start, w_end)
+    (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end)
     res = self.rfind(w_sub._value, start, end)
     return space.wrap(res)
 
@@ -511,7 +509,7 @@
 
 
 def str_index__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-    (self, start, end) =  _convert_idx_params(space, w_self, w_start, w_end)
+    (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end)
     res = self.find(w_sub._value, start, end)
     if res < 0:
         raise OperationError(space.w_ValueError,
@@ -521,7 +519,7 @@
 
 
 def str_rindex__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-    (self, start, end) =  _convert_idx_params(space, w_self, w_start, w_end)
+    (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end)
     res = self.rfind(w_sub._value, start, end)
     if res < 0:
         raise OperationError(space.w_ValueError,
@@ -728,7 +726,7 @@
         while 1:
             #no sophisticated linebreak support now, '\r' just for passing adapted CPython test
             if u_token[offset-1] == "\n" or u_token[offset-1] == "\r":
-                break;
+                break
             distance += 1
             offset -= 1
             if offset == 0:
@@ -738,7 +736,7 @@
         #print '<offset:%d distance:%d tabsize:%d token:%s>' % (offset, distance, u_tabsize, u_token)
         distance = (u_tabsize-distance) % u_tabsize
         if distance == 0:
-            distance=u_tabsize
+            distance = u_tabsize
 
     return distance
 
@@ -760,14 +758,14 @@
 
         for token in split:
             #print  "%d#%d -%s-" % (_tabindent(oldtoken,u_tabsize), u_tabsize, token)
-            u_expanded += " " * _tabindent(oldtoken,u_tabsize) + token
+            u_expanded += " " * _tabindent(oldtoken, u_tabsize) + token
             oldtoken = token
 
     return wrapstr(space, u_expanded)
 
 
 def str_splitlines__String_ANY(space, w_self, w_keepends):
-    u_keepends  = space.int_w(w_keepends)  # truth value, but type checked
+    u_keepends = space.int_w(w_keepends)  # truth value, but type checked
     data = w_self._value
     selflen = len(data)
     strs_w = []
@@ -876,7 +874,6 @@
     return wrapchar(space, str[ival])
 
 def getitem__String_Slice(space, w_str, w_slice):
-    w = space.wrap
     s = w_str._value
     length = len(s)
     start, stop, step, sl = w_slice.indices4(space, length)
diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -948,6 +948,9 @@
     def test_setitem_slice_performance(self):
         # because of a complexity bug, this used to take forever on a
         # translated pypy.  On CPython2.6 -A, it takes around 5 seconds.
+        import platform
+        if platform.machine().startswith('arm'):
+            skip("consumes too much memory for most ARM machines")
         if self.runappdirect:
             count = 16*1024*1024
         else:
diff --git a/pypy/pytest-A.py b/pypy/pytest-A.py
--- a/pypy/pytest-A.py
+++ b/pypy/pytest-A.py
@@ -6,6 +6,7 @@
             'interpreter/pyparser/test',
             'interpreter/test',
             'interpreter/test2',
+            'module/test_lib_pypy',
             'objspace/std/test',
     ],
 }
diff --git a/rpython/jit/backend/arm/test/test_fficall.py b/rpython/jit/backend/arm/test/test_fficall.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/arm/test/test_fficall.py
@@ -0,0 +1,23 @@
+import py
+from rpython.jit.metainterp.test import test_fficall
+from rpython.jit.backend.arm.test.support import JitARMMixin
+
+class TestFfiCall(JitARMMixin, test_fficall.FfiCallTests):
+    # for the individual tests see
+    # ====> ../../../metainterp/test/test_fficall.py
+
+    def _add_libffi_types_to_ll2types_maybe(self):
+        # this is needed by test_guard_not_forced_fails, because it produces a
+        # loop which reads the value of types.* in a variable, then a guard
+        # fail and we switch to blackhole: the problem is that at this point
+        # the blackhole interp has a real integer, but it needs to convert it
+        # back to a lltype pointer (which is handled by ll2ctypes, deeply in
+        # the logic). The workaround is to teach ll2ctypes in advance which
+        # are the addresses of the various types.* structures.
+        # Try to comment this code out and run the test to see how it fails :)
+        from rpython.rtyper.lltypesystem import rffi, lltype, ll2ctypes
+        from rpython.rlib.jit_libffi import types
+        for key, value in types.__dict__.iteritems():
+            if isinstance(value, lltype._ptr):
+                addr = rffi.cast(lltype.Signed, value)
+                ll2ctypes._int2obj[addr] = value
diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py
--- a/rpython/jit/backend/detect_cpu.py
+++ b/rpython/jit/backend/detect_cpu.py
@@ -115,6 +115,14 @@
     mod = __import__(modname, {}, {}, clsname)
     return getattr(mod, clsname)
 
+
+def getcpufeatures(backend_name="auto"):
+    """NOT_RPYTHON"""
+    cpucls = getcpuclass(backend_name)
+    return [attr[len('supports_'):] for attr in dir(cpucls)
+                            if attr.startswith('supports_')
+                                and getattr(cpucls, attr)]
+
 if __name__ == '__main__':
     print autodetect()
     print getcpuclassname()
diff --git a/rpython/jit/backend/test/test_detect_cpu.py b/rpython/jit/backend/test/test_detect_cpu.py
--- a/rpython/jit/backend/test/test_detect_cpu.py
+++ b/rpython/jit/backend/test/test_detect_cpu.py
@@ -31,3 +31,9 @@
 def test_detect_main_model_and_size_from_platform():
     info = autodetect_main_model_and_size()
     assert detect_main_model_and_size_from_platform() == info
+
+def test_getcpufeatures():
+    features = getcpufeatures()
+    assert isinstance(features, list)
+    for x in features:
+        assert x in ['floats', 'singlefloats', 'longlong']
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1751,7 +1751,7 @@
 
     def rewrite_op_jit_ffi_save_result(self, op):
         kind = op.args[0].value
-        assert kind in ('int', 'float')
+        assert kind in ('int', 'float', 'longlong', 'singlefloat')
         return SpaceOperation('libffi_save_result_%s' % kind, op.args[1:], None)
 
     def rewrite_op_jit_force_virtual(self, op):
diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -1351,24 +1351,39 @@
     def bhimpl_ll_read_timestamp():
         return read_timestamp()
 
-    @arguments("cpu", "i", "i", "i")
-    def bhimpl_libffi_save_result_int(self, cif_description, exchange_buffer, result):
-        ARRAY = lltype.Ptr(rffi.CArray(lltype.Signed))
-        cif_description = self.cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P)
-        exchange_buffer = self.cast_int_to_ptr(exchange_buffer, rffi.CCHARP)
+    def _libffi_save_result(self, cif_description, exchange_buffer, result):
+        ARRAY = lltype.Ptr(rffi.CArray(lltype.typeOf(result)))
+        cast_int_to_ptr = self.cpu.cast_int_to_ptr
+        cif_description = cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P)
+        exchange_buffer = cast_int_to_ptr(exchange_buffer, rffi.CCHARP)
         #
         data_out = rffi.ptradd(exchange_buffer, cif_description.exchange_result)
         rffi.cast(ARRAY, data_out)[0] = result
+    _libffi_save_result._annspecialcase_ = 'specialize:argtype(3)'
 
-    @arguments("cpu", "i", "i", "f")
-    def bhimpl_libffi_save_result_float(self, cif_description, exchange_buffer, result):
+    @arguments("self", "i", "i", "i")
+    def bhimpl_libffi_save_result_int(self, cif_description,
+                                      exchange_buffer, result):
+        self._libffi_save_result(cif_description, exchange_buffer, result)
+
+    @arguments("self", "i", "i", "f")
+    def bhimpl_libffi_save_result_float(self, cif_description,
+                                        exchange_buffer, result):
         result = longlong.getrealfloat(result)
-        ARRAY = lltype.Ptr(rffi.CArray(lltype.Float))
-        cif_description = self.cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P)
-        exchange_buffer = self.cast_int_to_ptr(exchange_buffer, rffi.CCHARP)
-        #
-        data_out = rffi.ptradd(exchange_buffer, cif_description.exchange_result)
-        rffi.cast(ARRAY, data_out)[0] = result
+        self._libffi_save_result(cif_description, exchange_buffer, result)
+
+    @arguments("self", "i", "i", "f")
+    def bhimpl_libffi_save_result_longlong(self, cif_description,
+                                           exchange_buffer, result):
+        # 32-bit only: 'result' is here a LongLong
+        assert longlong.is_longlong(lltype.typeOf(result))
+        self._libffi_save_result(cif_description, exchange_buffer, result)
+
+    @arguments("self", "i", "i", "i")
+    def bhimpl_libffi_save_result_singlefloat(self, cif_description,
+                                              exchange_buffer, result):
+        result = longlong.int2singlefloat(result)
+        self._libffi_save_result(cif_description, exchange_buffer, result)
 
 
     # ----------
diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -1190,8 +1190,8 @@
         return self.metainterp.execute_and_record(rop.READ_TIMESTAMP, None)
 
     @arguments("box", "box", "box")
-    def opimpl_libffi_save_result_int(self, box_cif_description, box_exchange_buffer,
-                                      box_result):
+    def _opimpl_libffi_save_result(self, box_cif_description,
+                                   box_exchange_buffer, box_result):
         from rpython.rtyper.lltypesystem import llmemory
         from rpython.rlib.jit_libffi import CIF_DESCRIPTION_P
         from rpython.jit.backend.llsupport.ffisupport import get_arg_descr
@@ -1208,10 +1208,14 @@
             assert ofs % itemsize == 0     # alignment check (result)
             self.metainterp.history.record(rop.SETARRAYITEM_RAW,
                                            [box_exchange_buffer,
-                                            ConstInt(ofs // itemsize), box_result],
+                                            ConstInt(ofs // itemsize),
+                                            box_result],
                                            None, descr)
 
-    opimpl_libffi_save_result_float = opimpl_libffi_save_result_int
+    opimpl_libffi_save_result_int         = _opimpl_libffi_save_result
+    opimpl_libffi_save_result_float       = _opimpl_libffi_save_result
+    opimpl_libffi_save_result_longlong    = _opimpl_libffi_save_result
+    opimpl_libffi_save_result_singlefloat = _opimpl_libffi_save_result
 
     # ------------------------------
 
diff --git a/rpython/jit/metainterp/test/support.py b/rpython/jit/metainterp/test/support.py
--- a/rpython/jit/metainterp/test/support.py
+++ b/rpython/jit/metainterp/test/support.py
@@ -14,7 +14,10 @@
 
 
 def _get_jitcodes(testself, CPUClass, func, values, type_system,
-                  supports_longlong=False, translationoptions={}, **kwds):
+                  supports_floats=True,
+                  supports_longlong=False,
+                  supports_singlefloats=False,
+                  translationoptions={}, **kwds):
     from rpython.jit.codewriter import support
 
     class FakeJitCell(object):
@@ -67,9 +70,16 @@
     cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()])
     cw.debug = True
     testself.cw = cw
+    if supports_floats and not cpu.supports_floats:
+        py.test.skip("this test requires supports_floats=True")
+    if supports_longlong and not cpu.supports_longlong:
+        py.test.skip("this test requires supports_longlong=True")
+    if supports_singlefloats and not cpu.supports_singlefloats:
+        py.test.skip("this test requires supports_singlefloats=True")
     policy = JitPolicy()
-    policy.set_supports_floats(True)
+    policy.set_supports_floats(supports_floats)
     policy.set_supports_longlong(supports_longlong)
+    policy.set_supports_singlefloats(supports_singlefloats)
     graphs = cw.find_all_graphs(policy)
     if kwds.get("backendopt"):
         backend_optimizations(rtyper.annotator.translator, graphs=graphs)
diff --git a/rpython/jit/metainterp/test/test_fficall.py b/rpython/jit/metainterp/test/test_fficall.py
--- a/rpython/jit/metainterp/test/test_fficall.py
+++ b/rpython/jit/metainterp/test/test_fficall.py
@@ -5,13 +5,13 @@
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.rtyper.annlowlevel import llhelper
 from rpython.jit.metainterp.test.support import LLJitMixin
-from rpython.jit.codewriter.longlong import is_longlong
+from rpython.jit.codewriter.longlong import is_longlong, is_64_bit
 from rpython.rlib import jit
 from rpython.rlib import jit_libffi
 from rpython.rlib.jit_libffi import (types, CIF_DESCRIPTION, FFI_TYPE_PP,
                                      jit_ffi_call, jit_ffi_save_result)
 from rpython.rlib.unroll import unrolling_iterable
-from rpython.rlib.rarithmetic import intmask, r_longlong
+from rpython.rlib.rarithmetic import intmask, r_longlong, r_singlefloat
 from rpython.rlib.longlong2float import float2longlong
 
 def get_description(atypes, rtype):
@@ -45,7 +45,12 @@
 
 class FfiCallTests(object):
 
-    def _run(self, atypes, rtype, avalues, rvalue, expected_call_release_gil=1):
+    def _run(self, atypes, rtype, avalues, rvalue,
+             expected_call_release_gil=1,
+             supports_floats=True,
+             supports_longlong=True,
+             supports_singlefloats=True):
+
         cif_description = get_description(atypes, rtype)
 
         def verify(*args):
@@ -67,7 +72,11 @@
             for avalue in unroll_avalues:
                 TYPE = rffi.CArray(lltype.typeOf(avalue))
                 data = rffi.ptradd(exchange_buffer, ofs)
-                assert rffi.cast(lltype.Ptr(TYPE), data)[0] == avalue
+                got = rffi.cast(lltype.Ptr(TYPE), data)[0]
+                if lltype.typeOf(avalue) is lltype.SingleFloat:
+                    got = float(got)
+                    avalue = float(avalue)
+                assert got == avalue
                 ofs += 16
             if rvalue is not None:
                 write_rvalue = rvalue
@@ -96,17 +105,30 @@
                 data = rffi.ptradd(exbuf, ofs)
                 res = rffi.cast(lltype.Ptr(TYPE), data)[0]
             lltype.free(exbuf, flavor='raw')
+            if lltype.typeOf(res) is lltype.SingleFloat:
+                res = float(res)
             return res
 
+        def matching_result(res, rvalue):
+            if rvalue is None:
+                return res == 654321
+            if isinstance(rvalue, r_singlefloat):
+                rvalue = float(rvalue)
+            return res == rvalue
+
         with FakeFFI(fake_call_impl_any):
             res = f()
-            assert res == rvalue or (res, rvalue) == (654321, None)
-            res = self.interp_operations(f, [])
+            assert matching_result(res, rvalue)
+            res = self.interp_operations(f, [],
+                            supports_floats = supports_floats,
+                          supports_longlong = supports_longlong,
+                      supports_singlefloats = supports_singlefloats)
             if is_longlong(FUNC.RESULT):
-                # longlongs are passed around as floats inside the JIT, we
-                # need to convert it back before checking the value
+                # longlongs are returned as floats, but that's just
+                # an inconvenience of interp_operations().  Normally both
+                # longlong and floats are passed around as longlongs.
                 res = float2longlong(res)
-            assert res == rvalue or (res, rvalue) == (654321, None)
+            assert matching_result(res, rvalue)
             self.check_operations_history(call_may_force=0,
                                           call_release_gil=expected_call_release_gil)
 
@@ -119,14 +141,24 @@
                       [-123456*j for j in range(i)],
                       -42434445)
 
-    def test_simple_call_float(self):
-        self._run([types.double] * 2, types.double, [45.6, 78.9], -4.2)
+    def test_simple_call_float(self, **kwds):
+        self._run([types.double] * 2, types.double, [45.6, 78.9], -4.2, **kwds)
 
-    def test_simple_call_longlong(self):
+    def test_simple_call_longlong(self, **kwds):
         maxint32 = 2147483647
         a = r_longlong(maxint32) + 1
         b = r_longlong(maxint32) + 2
-        self._run([types.slonglong] * 2, types.slonglong, [a, b], a)
+        self._run([types.slonglong] * 2, types.slonglong, [a, b], a, **kwds)
+
+    def test_simple_call_singlefloat_args(self):
+        self._run([types.float] * 2, types.double,
+                  [r_singlefloat(10.5), r_singlefloat(31.5)],
+                  -4.5)
+
+    def test_simple_call_singlefloat(self, **kwds):
+        self._run([types.float] * 2, types.float,
+                  [r_singlefloat(10.5), r_singlefloat(31.5)],
+                  r_singlefloat(-4.5), **kwds)
 
     def test_simple_call_longdouble(self):
         # longdouble is not supported, so we expect NOT to generate a call_release_gil
@@ -266,3 +298,20 @@
         assert res == math.sin(1.23)
 
         lltype.free(atypes, flavor='raw')
+
+    def test_simple_call_float_unsupported(self):
+        self.test_simple_call_float(supports_floats=False,
+                                    expected_call_release_gil=0)
+
+    def test_simple_call_longlong_unsupported(self):
+        self.test_simple_call_longlong(supports_longlong=False,
+                                       expected_call_release_gil=is_64_bit)
+
+    def test_simple_call_singlefloat_unsupported(self):
+        self.test_simple_call_singlefloat(supports_singlefloats=False,
+                                          expected_call_release_gil=0)
+
+    def test_simple_call_float_even_if_other_unsupported(self):
+        self.test_simple_call_float(supports_longlong=False,
+                                    supports_singlefloats=False)
+        # this is the default:      expected_call_release_gil=1
diff --git a/rpython/memory/gctransform/transform.py b/rpython/memory/gctransform/transform.py
--- a/rpython/memory/gctransform/transform.py
+++ b/rpython/memory/gctransform/transform.py
@@ -281,11 +281,11 @@
     def finish_helpers(self, backendopt=True):
         if self.translator is not None:
             self.mixlevelannotator.finish_annotate()
-        self.finished_helpers = True
         if self.translator is not None:
             self.mixlevelannotator.finish_rtype()
             if backendopt:
                 self.mixlevelannotator.backend_optimize()
+        self.finished_helpers = True
         # Make sure that the database also sees all finalizers now.
         # It is likely that the finalizers need special support there
         newgcdependencies = self.ll_finalizers_ptrs
diff --git a/rpython/rlib/jit_libffi.py b/rpython/rlib/jit_libffi.py
--- a/rpython/rlib/jit_libffi.py
+++ b/rpython/rlib/jit_libffi.py
@@ -2,6 +2,7 @@
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.rtyper.extregistry import ExtRegistryEntry
 from rpython.rlib import clibffi, jit
+from rpython.rlib.rarithmetic import r_longlong, r_singlefloat
 from rpython.rlib.nonconst import NonConstant
 
 
@@ -107,12 +108,14 @@
     reskind = types.getkind(cif_description.rtype)
     if reskind == 'v':
         jit_ffi_call_impl_void(cif_description, func_addr, exchange_buffer)
-    elif reskind == 'f' or reskind == 'L': # L is for longlongs, on 32bit
-        result = jit_ffi_call_impl_float(cif_description, func_addr, exchange_buffer)
-        jit_ffi_save_result('float', cif_description, exchange_buffer, result)
     elif reskind == 'i' or reskind == 'u':
-        result = jit_ffi_call_impl_int(cif_description, func_addr, exchange_buffer)
-        jit_ffi_save_result('int', cif_description, exchange_buffer, result)
+        _do_ffi_call_int(cif_description, func_addr, exchange_buffer)
+    elif reskind == 'f':
+        _do_ffi_call_float(cif_description, func_addr, exchange_buffer)
+    elif reskind == 'L': # L is for longlongs, on 32bit
+        _do_ffi_call_longlong(cif_description, func_addr, exchange_buffer)
+    elif reskind == 'S': # SingleFloat
+        _do_ffi_call_singlefloat(cif_description, func_addr, exchange_buffer)
     else:
         # the result kind is not supported: we disable the jit_ffi_call
         # optimization by calling directly jit_ffi_call_impl_any, so the JIT
@@ -123,6 +126,30 @@
         jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer)
 
 
+def _do_ffi_call_int(cif_description, func_addr, exchange_buffer):
+    result = jit_ffi_call_impl_int(cif_description, func_addr,
+                                   exchange_buffer)
+    jit_ffi_save_result('int', cif_description, exchange_buffer, result)
+
+def _do_ffi_call_float(cif_description, func_addr, exchange_buffer):
+    # a separate function in case the backend doesn't support floats
+    result = jit_ffi_call_impl_float(cif_description, func_addr,
+                                     exchange_buffer)
+    jit_ffi_save_result('float', cif_description, exchange_buffer, result)
+
+def _do_ffi_call_longlong(cif_description, func_addr, exchange_buffer):
+    # a separate function in case the backend doesn't support longlongs
+    result = jit_ffi_call_impl_longlong(cif_description, func_addr,
+                                        exchange_buffer)
+    jit_ffi_save_result('longlong', cif_description, exchange_buffer, result)
+
+def _do_ffi_call_singlefloat(cif_description, func_addr, exchange_buffer):
+    # a separate function in case the backend doesn't support singlefloats
+    result = jit_ffi_call_impl_singlefloat(cif_description, func_addr,
+                                           exchange_buffer)
+    jit_ffi_save_result('singlefloat', cif_description, exchange_buffer,result)
+
+
 # we must return a NonConstant else we get the constant -1 as the result of
 # the flowgraph, and the codewriter does not produce a box for the
 # result. Note that when not-jitted, the result is unused, but when jitted the
@@ -139,6 +166,16 @@
     return NonConstant(-1.0)
 
 @jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)")
+def jit_ffi_call_impl_longlong(cif_description, func_addr, exchange_buffer):
+    jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer)
+    return r_longlong(-1)
+
+ at jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)")
+def jit_ffi_call_impl_singlefloat(cif_description, func_addr, exchange_buffer):
+    jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer)
+    return r_singlefloat(-1.0)
+
+ at jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)")
 def jit_ffi_call_impl_void(cif_description, func_addr, exchange_buffer):
     jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer)
     return None
@@ -175,7 +212,7 @@
     def compute_result_annotation(self, kind_s, *args_s):
         from rpython.annotator import model as annmodel
         assert isinstance(kind_s, annmodel.SomeString)
-        assert kind_s.const in ('int', 'float')
+        assert kind_s.const in ('int', 'float', 'longlong', 'singlefloat')
 
     def specialize_call(self, hop):
         hop.exception_cannot_occur()
diff --git a/testrunner/runner.py b/testrunner/runner.py
--- a/testrunner/runner.py
+++ b/testrunner/runner.py
@@ -329,7 +329,7 @@
                     self.collect_one_testdir(testdirs, reldir,
                                    [self.reltoroot(t) for t in entries
                                     if self.is_test_py_file(t)])
-                    return
+                    break
 
         for p1 in entries:
             if p1.check(dir=1, link=0):


More information about the pypy-commit mailing list