Author: Tobias Pape <tob...@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) + +@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) + +@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): _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit