Author: Richard Plangger <planri...@gmail.com> Branch: s390x-backend Changeset: r80788:ccd0b940856e Date: 2015-11-20 11:01 +0100 http://bitbucket.org/pypy/pypy/changeset/ccd0b940856e/
Log: merged default diff too long, truncating to 2000 out of 6622 lines diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -17,3 +17,4 @@ 295ee98b69288471b0fcf2e0ede82ce5209eb90b release-2.6.0 f3ad1e1e1d6215e20d34bb65ab85ff9188c9f559 release-2.6.1 850edf14b2c75573720f59e95767335fb1affe55 release-4.0.0 +5f8302b8bf9f53056e40426f10c72151564e5b19 release-4.0.1 diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -56,14 +56,15 @@ Anders Chrigstrom Eric van Riet Paap Wim Lavrijsen + Richard Plangger Richard Emslie Alexander Schremmer Dan Villiom Podlaski Christiansen Lukas Diekmann Sven Hager Anders Lehmann + Remi Meier Aurelien Campeas - Remi Meier Niklaus Haldimann Camillo Bruni Laura Creighton @@ -87,7 +88,6 @@ Ludovic Aubry Jacob Hallen Jason Creighton - Richard Plangger Alex Martelli Michal Bendowski stian @@ -200,9 +200,12 @@ Alex Perry Vincent Legoll Alan McIntyre + Spenser Bauman Alexander Sedov Attila Gobi Christopher Pope + Devin Jeanpierre + Vaibhav Sood Christian Tismer Marc Abramowitz Dan Stromberg @@ -234,6 +237,7 @@ Lutz Paelike Lucio Torre Lars Wassermann + Philipp Rustemeuer Henrik Vendelbo Dan Buch Miguel de Val Borro @@ -244,6 +248,7 @@ Martin Blais Lene Wagner Tomo Cocoa + Kim Jin Su Toni Mattis Lucas Stadler Julian Berman @@ -253,6 +258,7 @@ Anna Katrina Dominguez William Leslie Bobby Impollonia + Faye Zhao t...@eistee.fritz.box Andrew Thompson Yusei Tahara @@ -283,6 +289,7 @@ shoma hosaka Daniel Neuhäuser Ben Mather + Niclas Olofsson halgari Boglarka Vezer Chris Pressey @@ -309,13 +316,16 @@ Stefan Marr jiaaro Mads Kiilerich + Richard Lancaster opassembler.py Antony Lee + Yaroslav Fedevych Jim Hunziker Markus Unterwaditzer Even Wiik Thomassen jbs squeaky + Zearin soareschen Kurt Griffiths Mike Bayer @@ -327,6 +337,7 @@ Anna Ravencroft Andrey Churin Dan Crosta + Tobias Diaz Julien Phalip Roman Podoliaka Dan Loewenherz diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO --- a/lib_pypy/cffi.egg-info/PKG-INFO +++ b/lib_pypy/cffi.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.3.0 +Version: 1.3.1 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py --- a/lib_pypy/cffi/__init__.py +++ b/lib_pypy/cffi/__init__.py @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "1.3.0" -__version_info__ = (1, 3, 0) +__version__ = "1.3.1" +__version_info__ = (1, 3, 1) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py --- a/lib_pypy/cffi/cparser.py +++ b/lib_pypy/cffi/cparser.py @@ -62,7 +62,8 @@ if csource.startswith('*', endpos): parts.append('('); closing += ')' level = 0 - for i in xrange(endpos, len(csource)): + i = endpos + while i < len(csource): c = csource[i] if c == '(': level += 1 @@ -73,6 +74,7 @@ elif c in ',;=': if level == 0: break + i += 1 csource = csource[endpos:i] + closing + csource[i:] #print repr(''.join(parts)+csource) parts.append(csource) diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py --- a/lib_pypy/cffi/model.py +++ b/lib_pypy/cffi/model.py @@ -514,12 +514,17 @@ if self.baseinttype is not None: return self.baseinttype.get_cached_btype(ffi, finishlist) # + from . import api if self.enumvalues: smallest_value = min(self.enumvalues) largest_value = max(self.enumvalues) else: - smallest_value = 0 - largest_value = 0 + import warnings + warnings.warn("%r has no values explicitly defined; next version " + "will refuse to guess which integer type it is " + "meant to be (unsigned/signed, int/long)" + % self._get_c_name()) + smallest_value = largest_value = 0 if smallest_value < 0: # needs a signed type sign = 1 candidate1 = PrimitiveType("int") diff --git a/pypy/doc/build.rst b/pypy/doc/build.rst --- a/pypy/doc/build.rst +++ b/pypy/doc/build.rst @@ -85,13 +85,16 @@ _ssl libssl +gdbm + libgdbm-dev + Make sure to have these libraries (with development headers) installed before building PyPy, otherwise the resulting binary will not contain these modules. On Debian, this is the command to install all build-time dependencies:: apt-get install gcc make libffi-dev pkg-config libz-dev libbz2-dev \ - libsqlite3-dev libncurses-dev libexpat1-dev libssl-dev + libsqlite3-dev libncurses-dev libexpat1-dev libssl-dev libgdbm-dev For the optional lzma module on PyPy3 you will also need ``liblzma-dev``. diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst --- a/pypy/doc/contributor.rst +++ b/pypy/doc/contributor.rst @@ -26,15 +26,15 @@ Anders Chrigstrom Eric van Riet Paap Wim Lavrijsen + Richard Plangger Richard Emslie Alexander Schremmer Dan Villiom Podlaski Christiansen Lukas Diekmann Sven Hager Anders Lehmann - Richard Plangger + Remi Meier Aurelien Campeas - Remi Meier Niklaus Haldimann Camillo Bruni Laura Creighton @@ -170,9 +170,12 @@ Alex Perry Vincent Legoll Alan McIntyre + Spenser Bauman Alexander Sedov Attila Gobi Christopher Pope + Devin Jeanpierre + Vaibhav Sood Christian Tismer Marc Abramowitz Dan Stromberg @@ -204,6 +207,7 @@ Lutz Paelike Lucio Torre Lars Wassermann + Philipp Rustemeuer Henrik Vendelbo Dan Buch Miguel de Val Borro @@ -214,6 +218,7 @@ Martin Blais Lene Wagner Tomo Cocoa + Kim Jin Su Toni Mattis Lucas Stadler Julian Berman @@ -223,6 +228,7 @@ Anna Katrina Dominguez William Leslie Bobby Impollonia + Faye Zhao t...@eistee.fritz.box Andrew Thompson Yusei Tahara @@ -280,13 +286,16 @@ Stefan Marr jiaaro Mads Kiilerich + Richard Lancaster opassembler.py Antony Lee + Yaroslav Fedevych Jim Hunziker Markus Unterwaditzer Even Wiik Thomassen jbs squeaky + Zearin soareschen Kurt Griffiths Mike Bayer @@ -298,6 +307,7 @@ Anna Ravencroft Andrey Churin Dan Crosta + Tobias Diaz Julien Phalip Roman Podoliaka Dan Loewenherz 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-4.0.1.rst release-4.0.0.rst release-2.6.1.rst release-2.6.0.rst diff --git a/pypy/doc/index-of-whatsnew.rst b/pypy/doc/index-of-whatsnew.rst --- a/pypy/doc/index-of-whatsnew.rst +++ b/pypy/doc/index-of-whatsnew.rst @@ -7,6 +7,7 @@ .. toctree:: whatsnew-head.rst + whatsnew-4.0.1.rst whatsnew-4.0.0.rst whatsnew-2.6.1.rst whatsnew-2.6.0.rst diff --git a/pypy/doc/release-4.0.1.rst b/pypy/doc/release-4.0.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-4.0.1.rst @@ -0,0 +1,106 @@ +========== +PyPy 4.0.1 +========== + +We have released PyPy 4.0.1, three weeks after PyPy 4.0.0. We have fixed +a few critical bugs in the JIT compiled code, reported by users. We therefore +encourage all users of PyPy to update to this version. There are a few minor +enhancements in this version as well. + +You can download the PyPy 4.0.1 release here: + + http://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project. + +We would also like to thank our contributors and +encourage new people to join the project. PyPy has many +layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation +improvements, tweaking popular `modules`_ to run on pypy, or general `help`_ +with making RPython's JIT even better. + +CFFI +==== + +While not applicable only to PyPy, `cffi`_ is arguably our most significant +contribution to the python ecosystem. PyPy 4.0.1 ships with +`cffi-1.3.1`_ with the improvements it brings. + +.. _`PyPy`: http://doc.pypy.org +.. _`RPython`: https://rpython.readthedocs.org +.. _`cffi`: https://cffi.readthedocs.org +.. _`cffi-1.3.1`: http://cffi.readthedocs.org/en/latest/whatsnew.html#v1-3-1 +.. _`modules`: http://doc.pypy.org/en/latest/project-ideas.html#make-more-python-modules-pypy-friendly +.. _`help`: http://doc.pypy.org/en/latest/project-ideas.html +.. _`numpy`: https://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 and cpython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +We also welcome developers of other +`dynamic languages`_ to see what RPython can do for them. + +This release supports **x86** machines on most common operating systems +(Linux 32/64, Mac OS X 64, Windows 32, OpenBSD, freebsd), +newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux, and the +big- and little-endian variants of **ppc64** running Linux. + +.. _`pypy and cpython 2.7.x`: http://speed.pypy.org +.. _`dynamic languages`: http://pypyjs.org + +Other Highlights (since 4.0.0 released three weeks ago) +======================================================= + +* Bug Fixes + + * Fix a bug when unrolling double loops in JITted code + + * Fix multiple memory leaks in the ssl module, one of which affected + `cpython` as well (thanks to Alex Gaynor for pointing those out) + + * Use pkg-config to find ssl headers on OS-X + + * Issues reported with our previous release were resolved_ after reports from users on + our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at + #pypy + +* New features: + + * Internal cleanup of RPython class handling + + * Support stackless and greenlets on PPC machines + + * Improve debug logging in subprocesses: use PYPYLOG=jit:log.%d + for example to have all subprocesses write the JIT log to a file + called 'log.%d', with '%d' replaced with the subprocess' PID. + + * Support PyOS_double_to_string in our cpyext capi compatibility layer + +* Numpy: + + * Improve support for __array_interface__ + + * Propagate NAN mantissas through float16-float32-float64 conversions + + +* Performance improvements and refactorings: + + * Improvements in slicing byte arrays + + * Improvements in enumerate() + + * Silence some warnings while translating + +.. _resolved: http://doc.pypy.org/en/latest/whatsnew-4.0.1.html + +Please update, and continue to help us make PyPy better. + +Cheers + +The PyPy Team + diff --git a/pypy/doc/tool/makecontributor.py b/pypy/doc/tool/makecontributor.py --- a/pypy/doc/tool/makecontributor.py +++ b/pypy/doc/tool/makecontributor.py @@ -69,7 +69,9 @@ 'Rami Chowdhury': ['necaris'], 'Stanislaw Halik':['w31rd0'], 'Wenzhu Man':['wenzhu man', 'wenzhuman'], - 'Anton Gulenko':['anton gulenko'], + 'Anton Gulenko':['anton gulenko', 'anton_gulenko'], + 'Richard Lancaster':['richardlancaster'], + 'William Leslie':['William ML Leslie'], } alias_map = {} diff --git a/pypy/doc/whatsnew-4.0.1.rst b/pypy/doc/whatsnew-4.0.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/whatsnew-4.0.1.rst @@ -0,0 +1,35 @@ +========================= +What's new in PyPy 4.0.1 +========================= + +.. this is a revision shortly after release-4.0.0 +.. startrev: 57c9a47c70f6 + +.. branch: 2174-fix-osx-10-11-translation + +Use pkg-config to find ssl headers on OS-X + +.. branch: Zearin/minor-whatsnewrst-markup-tweaks-edited-o-1446387512092 + +.. branch: ppc-stacklet + +The PPC machines now support the _continuation module (stackless, greenlets) + +.. branch: int_0/i-need-this-library-to-build-on-ubuntu-1-1446717626227 + +Document that libgdbm-dev is required for translation/packaging + +.. branch: propogate-nans + +Ensure that ndarray conversion from int16->float16->float32->float16->int16 +preserves all int16 values, even across nan conversions. Also fix argmax, argmin +for nan comparisons + +.. branch: array_interface + +Support common use-cases for __array_interface__, passes upstream tests + +.. branch: no-class-specialize + +Some refactoring of class handling in the annotator. +Remove class specialisation and _settled_ flag. 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 @@ -2,15 +2,6 @@ What's new in PyPy 4.0.+ ========================= -.. this is a revision shortly after release-4.0.0 -.. startrev: 57c9a47c70f6 +.. this is a revision shortly after release-4.0.1 +.. startrev: 4b5c840d0da2 -.. branch: 2174-fix-osx-10-11-translation - -Use pkg-config to find ssl headers on OS-X - -.. branch: Zearin/minor-whatsnewrst-markup-tweaks-edited-o-1446387512092 - -.. branch: ppc-stacklet - -The PPC machines now support the _continuation module (stackless, greenlets) diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -28,7 +28,6 @@ """This is the abstract root class of all wrapped objects that live in a 'normal' object space like StdObjSpace.""" __slots__ = () - _settled_ = True user_overridden_class = False def getdict(self, space): @@ -392,7 +391,7 @@ self.check_signal_action = None # changed by the signal module self.user_del_action = UserDelAction(self) self._code_of_sys_exc_info = None - + # can be overridden to a subclass self.initialize() diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -50,6 +50,9 @@ kwargname = varnames[argcount] if code.co_flags & CO_VARKEYWORDS else None return Signature(argnames, varargname, kwargname) +class CodeHookCache(object): + def __init__(self, space): + self._code_hook = None class PyCode(eval.Code): "CPython-style code objects." @@ -86,6 +89,15 @@ self._signature = cpython_code_signature(self) self._initialize() self._init_ready() + self.new_code_hook() + + def new_code_hook(self): + code_hook = self.space.fromcache(CodeHookCache)._code_hook + if code_hook is not None: + try: + self.space.call_function(code_hook, self) + except OperationError, e: + e.write_unraisable(self.space, "new_code_hook()") def _initialize(self): if self.co_cellvars: diff --git a/pypy/interpreter/test/test_zzpickle_and_slow.py b/pypy/interpreter/test/test_zzpickle_and_slow.py --- a/pypy/interpreter/test/test_zzpickle_and_slow.py +++ b/pypy/interpreter/test/test_zzpickle_and_slow.py @@ -390,15 +390,20 @@ def test_pickle_enum(self): import pickle - e = enumerate(range(10)) + e = enumerate(range(100, 106)) e.next() e.next() pckl = pickle.dumps(e) result = pickle.loads(pckl) - e.next() - result.next() + res = e.next() + assert res == (2, 102) + res = result.next() + assert res == (2, 102) assert type(e) is type(result) - assert list(e) == list(result) + res = list(e) + assert res == [(3, 103), (4, 104), (5, 105)] + res = list(result) + assert res == [(3, 103), (4, 104), (5, 105)] def test_pickle_xrangeiter(self): import pickle diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -8,7 +8,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.interpreter.typedef import TypeDef -from rpython.rlib import jit +from rpython.rlib import jit, rarithmetic from rpython.rlib.objectmodel import specialize from rpython.rlib.rarithmetic import r_uint, intmask from rpython.rlib.rbigint import rbigint @@ -229,27 +229,70 @@ return min_max(space, __args__, "min") + class W_Enumerate(W_Root): - def __init__(self, w_iter, w_start): - self.w_iter = w_iter + def __init__(self, w_iter_or_list, start, w_start): + # 'w_index' should never be a wrapped int here; if it would be, + # then it is actually None and the unwrapped int is in 'index'. + self.w_iter_or_list = w_iter_or_list + self.index = start self.w_index = w_start def descr___new__(space, w_subtype, w_iterable, w_start=None): - self = space.allocate_instance(W_Enumerate, w_subtype) + from pypy.objspace.std.listobject import W_ListObject + if w_start is None: - w_start = space.wrap(0) + start = 0 else: w_start = space.index(w_start) - self.__init__(space.iter(w_iterable), w_start) + if space.is_w(space.type(w_start), space.w_int): + start = space.int_w(w_start) + w_start = None + else: + start = -1 + + if start == 0 and type(w_iterable) is W_ListObject: + w_iter = w_iterable + else: + w_iter = space.iter(w_iterable) + + self = space.allocate_instance(W_Enumerate, w_subtype) + self.__init__(w_iter, start, w_start) return space.wrap(self) def descr___iter__(self, space): return space.wrap(self) def descr_next(self, space): - w_item = space.next(self.w_iter) + from pypy.objspace.std.listobject import W_ListObject w_index = self.w_index - self.w_index = space.add(w_index, space.wrap(1)) + w_iter_or_list = self.w_iter_or_list + w_item = None + if w_index is None: + index = self.index + if type(w_iter_or_list) is W_ListObject: + try: + w_item = w_iter_or_list.getitem(index) + except IndexError: + self.w_iter_or_list = None + raise OperationError(space.w_StopIteration, space.w_None) + self.index = index + 1 + elif w_iter_or_list is None: + raise OperationError(space.w_StopIteration, space.w_None) + else: + try: + newval = rarithmetic.ovfcheck(index + 1) + except OverflowError: + w_index = space.wrap(index) + self.w_index = space.add(w_index, space.wrap(1)) + self.index = -1 + else: + self.index = newval + w_index = space.wrap(index) + else: + self.w_index = space.add(w_index, space.wrap(1)) + if w_item is None: + w_item = space.next(self.w_iter_or_list) return space.newtuple([w_index, w_item]) def descr___reduce__(self, space): @@ -257,12 +300,20 @@ w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) w_new_inst = mod.get('enumerate_new') - w_info = space.newtuple([self.w_iter, self.w_index]) + w_index = self.w_index + if w_index is None: + w_index = space.wrap(self.index) + w_info = space.newtuple([self.w_iter_or_list, w_index]) return space.newtuple([w_new_inst, w_info]) # exported through _pickle_support -def _make_enumerate(space, w_iter, w_index): - return space.wrap(W_Enumerate(w_iter, w_index)) +def _make_enumerate(space, w_iter_or_list, w_index): + if space.is_w(space.type(w_index), space.w_int): + index = space.int_w(w_index) + w_index = None + else: + index = -1 + return space.wrap(W_Enumerate(w_iter_or_list, index, w_index)) W_Enumerate.typedef = TypeDef("enumerate", __new__=interp2app(W_Enumerate.descr___new__.im_func), diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -264,6 +264,7 @@ raises(StopIteration,x.next) def test_enumerate(self): + import sys seq = range(2,4) enum = enumerate(seq) assert enum.next() == (0, 2) @@ -274,6 +275,15 @@ enum = enumerate(range(5), 2) assert list(enum) == zip(range(2, 7), range(5)) + enum = enumerate(range(2), 2**100) + assert list(enum) == [(2**100, 0), (2**100+1, 1)] + + enum = enumerate(range(2), sys.maxint) + assert list(enum) == [(sys.maxint, 0), (sys.maxint+1, 1)] + + raises(TypeError, enumerate, range(2), 5.5) + + def test_next(self): x = iter(['a', 'b', 'c']) assert next(x) == 'a' 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 @@ -86,6 +86,7 @@ 'specialized_zip_2_lists' : 'interp_magic.specialized_zip_2_lists', 'set_debug' : 'interp_magic.set_debug', 'locals_to_fast' : 'interp_magic.locals_to_fast', + 'set_code_callback' : 'interp_magic.set_code_callback', 'save_module_content_for_future_reload': 'interp_magic.save_module_content_for_future_reload', } diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -1,5 +1,6 @@ from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.gateway import unwrap_spec +from pypy.interpreter.pycode import CodeHookCache from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.mixedmodule import MixedModule from rpython.rlib.objectmodel import we_are_translated @@ -151,3 +152,10 @@ def specialized_zip_2_lists(space, w_list1, w_list2): from pypy.objspace.std.specialisedtupleobject import specialized_zip_2_lists return specialized_zip_2_lists(space, w_list1, w_list2) + +def set_code_callback(space, w_callable): + cache = space.fromcache(CodeHookCache) + if space.is_none(w_callable): + cache._code_hook = None + else: + cache._code_hook = w_callable \ No newline at end of file diff --git a/pypy/module/__pypy__/test/test_magic.py b/pypy/module/__pypy__/test/test_magic.py --- a/pypy/module/__pypy__/test/test_magic.py +++ b/pypy/module/__pypy__/test/test_magic.py @@ -13,3 +13,21 @@ # sys.dont_write_bytecode = d __pypy__.save_module_content_for_future_reload(sys) + + def test_new_code_hook(self): + l = [] + + def callable(code): + l.append(code) + + import __pypy__ + __pypy__.set_code_callback(callable) + d = {} + try: + exec """ +def f(): + pass +""" in d + finally: + __pypy__.set_code_callback(None) + assert d['f'].__code__ in l \ No newline at end of file diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -2,7 +2,7 @@ from pypy.interpreter.mixedmodule import MixedModule from rpython.rlib import rdynload, clibffi -VERSION = "1.3.0" +VERSION = "1.3.1" FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI try: diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py --- a/pypy/module/_cffi_backend/ffi_obj.py +++ b/pypy/module/_cffi_backend/ffi_obj.py @@ -448,7 +448,7 @@ 'alloc' is called with the size as argument. If it returns NULL, a MemoryError is raised. 'free' is called with the result of 'alloc' -as argument. Both can be either Python function or directly C +as argument. Both can be either Python functions or directly C functions. If 'free' is None, then no free function is called. If both 'alloc' and 'free' are None, the default is used. diff --git a/pypy/module/_cffi_backend/src/parse_c_type.c b/pypy/module/_cffi_backend/src/parse_c_type.c --- a/pypy/module/_cffi_backend/src/parse_c_type.c +++ b/pypy/module/_cffi_backend/src/parse_c_type.c @@ -4,6 +4,7 @@ #include <errno.h> #if defined(_MSC_VER) +# define MS_WIN32 typedef size_t uintptr_t; #else # include <stdint.h> diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -1,7 +1,7 @@ # ____________________________________________________________ import sys -assert __version__ == "1.3.0", ("This test_c.py file is for testing a version" +assert __version__ == "1.3.1", ("This test_c.py file is for testing a version" " of cffi that differs from the one that we" " get from 'import _cffi_backend'") if sys.version_info < (3,): diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py --- a/pypy/module/_cffi_backend/test/test_recompiler.py +++ b/pypy/module/_cffi_backend/test/test_recompiler.py @@ -16,8 +16,8 @@ from cffi import ffiplatform except ImportError: py.test.skip("system cffi module not found or older than 1.0.0") - if cffi.__version_info__ < (1, 2, 0): - py.test.skip("system cffi module needs to be at least 1.2.0") + if cffi.__version_info__ < (1, 3, 0): + py.test.skip("system cffi module needs to be at least 1.3.0") space.appexec([], """(): import _cffi_backend # force it to be initialized """) diff --git a/pypy/module/_minimal_curses/interp_curses.py b/pypy/module/_minimal_curses/interp_curses.py --- a/pypy/module/_minimal_curses/interp_curses.py +++ b/pypy/module/_minimal_curses/interp_curses.py @@ -13,7 +13,7 @@ def __init__(self, msg): self.msg = msg -from rpython.annotator.description import FORCE_ATTRIBUTES_INTO_CLASSES +from rpython.annotator.classdesc import FORCE_ATTRIBUTES_INTO_CLASSES from rpython.annotator.model import SomeString # this is necessary due to annmixlevel diff --git a/pypy/module/_multiprocessing/interp_win32.py b/pypy/module/_multiprocessing/interp_win32.py --- a/pypy/module/_multiprocessing/interp_win32.py +++ b/pypy/module/_multiprocessing/interp_win32.py @@ -17,7 +17,7 @@ NMPWAIT_WAIT_FOREVER ERROR_PIPE_CONNECTED ERROR_SEM_TIMEOUT ERROR_PIPE_BUSY ERROR_NO_SYSTEM_RESOURCES ERROR_BROKEN_PIPE ERROR_MORE_DATA - ERROR_ALREADY_EXISTS + ERROR_ALREADY_EXISTS ERROR_NO_DATA """.split() class CConfig: 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 @@ -1,4 +1,4 @@ -from rpython.rlib import rpoll, rsocket, rthread, rweakref +from rpython.rlib import rpoll, rsocket, rthread, rweakref, rgc from rpython.rlib.rarithmetic import intmask, widen, r_uint from rpython.rlib.ropenssl import * from pypy.module._socket import interp_socket @@ -852,55 +852,58 @@ names = rffi.cast(GENERAL_NAMES, method[0].c_d2i( null, p_ptr, length)) - for j in range(libssl_sk_GENERAL_NAME_num(names)): - # Get a rendering of each name in the set of names + try: + for j in range(libssl_sk_GENERAL_NAME_num(names)): + # Get a rendering of each name in the set of names - name = libssl_sk_GENERAL_NAME_value(names, j) - gntype = intmask(name.c_type) - if gntype == GEN_DIRNAME: - # we special-case DirName as a tuple of tuples of - # attributes - dirname = libssl_pypy_GENERAL_NAME_dirn(name) - w_t = space.newtuple([ - space.wrap("DirName"), - _create_tuple_for_X509_NAME(space, dirname) - ]) - elif gntype in (GEN_EMAIL, GEN_DNS, GEN_URI): - # GENERAL_NAME_print() doesn't handle NULL bytes in - # ASN1_string correctly, CVE-2013-4238 - if gntype == GEN_EMAIL: - v = space.wrap("email") - elif gntype == GEN_DNS: - v = space.wrap("DNS") - elif gntype == GEN_URI: - v = space.wrap("URI") + name = libssl_sk_GENERAL_NAME_value(names, j) + gntype = intmask(name.c_type) + if gntype == GEN_DIRNAME: + # we special-case DirName as a tuple of tuples of + # attributes + dirname = libssl_pypy_GENERAL_NAME_dirn(name) + w_t = space.newtuple([ + space.wrap("DirName"), + _create_tuple_for_X509_NAME(space, dirname) + ]) + elif gntype in (GEN_EMAIL, GEN_DNS, GEN_URI): + # GENERAL_NAME_print() doesn't handle NULL bytes in + # ASN1_string correctly, CVE-2013-4238 + if gntype == GEN_EMAIL: + v = space.wrap("email") + elif gntype == GEN_DNS: + v = space.wrap("DNS") + elif gntype == GEN_URI: + v = space.wrap("URI") + else: + assert False + as_ = libssl_pypy_GENERAL_NAME_dirn(name) + as_ = rffi.cast(ASN1_STRING, as_) + buf = libssl_ASN1_STRING_data(as_) + length = libssl_ASN1_STRING_length(as_) + w_t = space.newtuple([ + v, space.wrap(rffi.charpsize2str(buf, length))]) else: - assert False - as_ = libssl_pypy_GENERAL_NAME_dirn(name) - as_ = rffi.cast(ASN1_STRING, as_) - buf = libssl_ASN1_STRING_data(as_) - length = libssl_ASN1_STRING_length(as_) - w_t = space.newtuple([ - v, space.wrap(rffi.charpsize2str(buf, length))]) - else: - # for everything else, we use the OpenSSL print form - if gntype not in (GEN_OTHERNAME, GEN_X400, GEN_EDIPARTY, - GEN_IPADD, GEN_RID): - space.warn(space.wrap("Unknown general name type"), - space.w_RuntimeWarning) - libssl_BIO_reset(biobuf) - libssl_GENERAL_NAME_print(biobuf, name) - with lltype.scoped_alloc(rffi.CCHARP.TO, 2048) as buf: - length = libssl_BIO_gets(biobuf, buf, 2047) - if length < 0: - raise _ssl_seterror(space, None, 0) + # for everything else, we use the OpenSSL print form + if gntype not in (GEN_OTHERNAME, GEN_X400, GEN_EDIPARTY, + GEN_IPADD, GEN_RID): + space.warn(space.wrap("Unknown general name type"), + space.w_RuntimeWarning) + libssl_BIO_reset(biobuf) + libssl_GENERAL_NAME_print(biobuf, name) + with lltype.scoped_alloc(rffi.CCHARP.TO, 2048) as buf: + length = libssl_BIO_gets(biobuf, buf, 2047) + if length < 0: + raise _ssl_seterror(space, None, 0) - v = rffi.charpsize2str(buf, length) - v1, v2 = v.split(':', 1) - w_t = space.newtuple([space.wrap(v1), - space.wrap(v2)]) + v = rffi.charpsize2str(buf, length) + v1, v2 = v.split(':', 1) + w_t = space.newtuple([space.wrap(v1), + space.wrap(v2)]) - alt_names_w.append(w_t) + alt_names_w.append(w_t) + finally: + libssl_pypy_GENERAL_NAME_pop_free(names) finally: libssl_BIO_free(biobuf) @@ -921,8 +924,11 @@ length = libssl_ASN1_STRING_to_UTF8(buf_ptr, value) if length < 0: raise _ssl_seterror(space, None, 0) - w_value = space.wrap(rffi.charpsize2str(buf_ptr[0], length)) - w_value = space.call_method(w_value, "decode", space.wrap("utf-8")) + try: + w_value = space.wrap(rffi.charpsize2str(buf_ptr[0], length)) + w_value = space.call_method(w_value, "decode", space.wrap("utf-8")) + finally: + libssl_OPENSSL_free(buf_ptr[0]) return space.newtuple([w_name, w_value]) @@ -930,9 +936,10 @@ def _get_aia_uri(space, certificate, nid): info = rffi.cast(AUTHORITY_INFO_ACCESS, libssl_X509_get_ext_d2i( certificate, NID_info_access, None, None)) - if not info or libssl_sk_ACCESS_DESCRIPTION_num(info) == 0: - return try: + if not info or libssl_sk_ACCESS_DESCRIPTION_num(info) == 0: + return + result_w = [] for i in range(libssl_sk_ACCESS_DESCRIPTION_num(info)): ad = libssl_sk_ACCESS_DESCRIPTION_value(info, i) @@ -962,20 +969,24 @@ if not dps: return None - cdp_w = [] - for i in range(libssl_sk_DIST_POINT_num(dps)): - dp = libssl_sk_DIST_POINT_value(dps, i) - gns = libssl_pypy_DIST_POINT_fullname(dp) + try: + cdp_w = [] + for i in range(libssl_sk_DIST_POINT_num(dps)): + dp = libssl_sk_DIST_POINT_value(dps, i) + gns = libssl_pypy_DIST_POINT_fullname(dp) - for j in range(libssl_sk_GENERAL_NAME_num(gns)): - name = libssl_sk_GENERAL_NAME_value(gns, j) - gntype = intmask(name.c_type) - if gntype != GEN_URI: - continue - uri = libssl_pypy_GENERAL_NAME_uri(name) - length = intmask(uri.c_length) - s_uri = rffi.charpsize2str(uri.c_data, length) - cdp_w.append(space.wrap(s_uri)) + for j in range(libssl_sk_GENERAL_NAME_num(gns)): + name = libssl_sk_GENERAL_NAME_value(gns, j) + gntype = intmask(name.c_type) + if gntype != GEN_URI: + continue + uri = libssl_pypy_GENERAL_NAME_uri(name) + length = intmask(uri.c_length) + s_uri = rffi.charpsize2str(uri.c_data, length) + cdp_w.append(space.wrap(s_uri)) + finally: + if OPENSSL_VERSION_NUMBER < 0x10001000: + libssl_sk_DIST_POINT_free(dps) return space.newtuple(cdp_w[:]) def checkwait(space, w_sock, writing): @@ -1270,6 +1281,7 @@ if not ctx: raise ssl_error(space, "failed to allocate SSL context") + rgc.add_memory_pressure(10 * 1024 * 1024) self = space.allocate_instance(_SSLContext, w_subtype) self.ctx = ctx self.check_hostname = False @@ -1296,6 +1308,9 @@ return self + def __del__(self): + libssl_SSL_CTX_free(self.ctx) + @unwrap_spec(server_side=int) def descr_wrap_socket(self, space, w_sock, server_side, w_server_hostname=None, w_ssl_sock=None): return _SSLSocket.descr_new(space, self, w_sock, server_side, w_server_hostname, w_ssl_sock) diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py --- a/pypy/module/cpyext/pystrtod.py +++ b/pypy/module/cpyext/pystrtod.py @@ -5,10 +5,23 @@ from rpython.rlib import rdtoa from rpython.rlib import rfloat from rpython.rlib import rposix, jit +from rpython.rlib.rarithmetic import intmask from rpython.rtyper.lltypesystem import lltype from rpython.rtyper.lltypesystem import rffi +# PyOS_double_to_string's "type", if non-NULL, will be set to one of: +Py_DTST_FINITE = 0 +Py_DTST_INFINITE = 1 +Py_DTST_NAN = 2 + +# Match the "type" back to values in CPython +DOUBLE_TO_STRING_TYPES_MAP = { + rfloat.DIST_FINITE: Py_DTST_FINITE, + rfloat.DIST_INFINITY: Py_DTST_INFINITE, + rfloat.DIST_NAN: Py_DTST_NAN +} + @cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) @jit.dont_look_inside # direct use of _get_errno() def PyOS_string_to_double(space, s, endptr, w_overflow_exception): @@ -68,3 +81,42 @@ finally: if not user_endptr: lltype.free(endptr, flavor='raw') + +@cpython_api([rffi.DOUBLE, lltype.Char, rffi.INT_real, rffi.INT_real, rffi.INTP], rffi.CCHARP) +def PyOS_double_to_string(space, val, format_code, precision, flags, ptype): + """Convert a double val to a string using supplied + format_code, precision, and flags. + + format_code must be one of 'e', 'E', 'f', 'F', + 'g', 'G' or 'r'. For 'r', the supplied precision + must be 0 and is ignored. The 'r' format code specifies the + standard repr() format. + + flags can be zero or more of the values Py_DTSF_SIGN, + Py_DTSF_ADD_DOT_0, or Py_DTSF_ALT, or-ed together: + + Py_DTSF_SIGN means to always precede the returned string with a sign + character, even if val is non-negative. + + Py_DTSF_ADD_DOT_0 means to ensure that the returned string will not look + like an integer. + + Py_DTSF_ALT means to apply "alternate" formatting rules. See the + documentation for the PyOS_snprintf() '#' specifier for + details. + + If ptype is non-NULL, then the value it points to will be set to one of + Py_DTST_FINITE, Py_DTST_INFINITE, or Py_DTST_NAN, signifying that + val is a finite number, an infinite number, or not a number, respectively. + + The return value is a pointer to buffer with the converted string or + NULL if the conversion failed. The caller is responsible for freeing the + returned string by calling PyMem_Free(). + """ + buffer, rtype = rfloat.double_to_string(val, format_code, + intmask(precision), + intmask(flags)) + if ptype != lltype.nullptr(rffi.INTP.TO): + ptype[0] = rffi.cast(rffi.INT, DOUBLE_TO_STRING_TYPES_MAP[rtype]) + bufp = rffi.str2charp(buffer) + return bufp diff --git a/pypy/module/cpyext/test/test_pystrtod.py b/pypy/module/cpyext/test/test_pystrtod.py --- a/pypy/module/cpyext/test/test_pystrtod.py +++ b/pypy/module/cpyext/test/test_pystrtod.py @@ -1,5 +1,6 @@ import math +from pypy.module.cpyext import pystrtod from pypy.module.cpyext.test.test_api import BaseApiTest from rpython.rtyper.lltypesystem import rffi from rpython.rtyper.lltypesystem import lltype @@ -91,3 +92,76 @@ api.PyErr_Clear() rffi.free_charp(s) lltype.free(endp, flavor='raw') + + +class TestPyOS_double_to_string(BaseApiTest): + + def test_format_code(self, api): + ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') + r = api.PyOS_double_to_string(150.0, 'e', 1, 0, ptype) + assert '1.5e+02' == rffi.charp2str(r) + type_value = rffi.cast(lltype.Signed, ptype[0]) + assert pystrtod.Py_DTST_FINITE == type_value + rffi.free_charp(r) + lltype.free(ptype, flavor='raw') + + def test_precision(self, api): + ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') + r = api.PyOS_double_to_string(3.14159269397, 'g', 5, 0, ptype) + assert '3.1416' == rffi.charp2str(r) + type_value = rffi.cast(lltype.Signed, ptype[0]) + assert pystrtod.Py_DTST_FINITE == type_value + rffi.free_charp(r) + lltype.free(ptype, flavor='raw') + + def test_flags_sign(self, api): + ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') + r = api.PyOS_double_to_string(-3.14, 'g', 3, 1, ptype) + assert '-3.14' == rffi.charp2str(r) + type_value = rffi.cast(lltype.Signed, ptype[0]) + assert pystrtod.Py_DTST_FINITE == type_value + rffi.free_charp(r) + lltype.free(ptype, flavor='raw') + + def test_flags_add_dot_0(self, api): + ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') + r = api.PyOS_double_to_string(3, 'g', 5, 2, ptype) + assert '3.0' == rffi.charp2str(r) + type_value = rffi.cast(lltype.Signed, ptype[0]) + assert pystrtod.Py_DTST_FINITE == type_value + rffi.free_charp(r) + lltype.free(ptype, flavor='raw') + + def test_flags_alt(self, api): + ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') + r = api.PyOS_double_to_string(314., 'g', 3, 4, ptype) + assert '314.' == rffi.charp2str(r) + type_value = rffi.cast(lltype.Signed, ptype[0]) + assert pystrtod.Py_DTST_FINITE == type_value + rffi.free_charp(r) + lltype.free(ptype, flavor='raw') + + def test_ptype_nan(self, api): + ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') + r = api.PyOS_double_to_string(float('nan'), 'g', 3, 4, ptype) + assert 'nan' == rffi.charp2str(r) + type_value = rffi.cast(lltype.Signed, ptype[0]) + assert pystrtod.Py_DTST_NAN == type_value + rffi.free_charp(r) + lltype.free(ptype, flavor='raw') + + def test_ptype_infinity(self, api): + ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') + r = api.PyOS_double_to_string(1e200 * 1e200, 'g', 0, 0, ptype) + assert 'inf' == rffi.charp2str(r) + type_value = rffi.cast(lltype.Signed, ptype[0]) + assert pystrtod.Py_DTST_INFINITE == type_value + rffi.free_charp(r) + lltype.free(ptype, flavor='raw') + + def test_ptype_null(self, api): + ptype = lltype.nullptr(rffi.INTP.TO) + r = api.PyOS_double_to_string(3.14, 'g', 3, 0, ptype) + assert '3.14' == rffi.charp2str(r) + assert ptype == lltype.nullptr(rffi.INTP.TO) + rffi.free_charp(r) \ No newline at end of file diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -156,9 +156,6 @@ put_tuple_w(TYPE, tuple_w) puts tuple_w, an unwrapped list of wrapped objects """ - # _annspecialcase_ = "specialize:ctr_location" # polymorphic - # does not work with subclassing - def __init__(self, space, writer, version): self.space = space ## self.put = putfunc diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -371,6 +371,8 @@ @specialize.arg(2) def call_method(self, w_obj, s, *args): # XXX even the hacks have hacks + if s == 'size': # used in _array() but never called by tests + return IntObject(0) return getattr(w_obj, 'descr_' + s)(self, *args) @specialize.arg(1) diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py --- a/pypy/module/micronumpy/ctors.py +++ b/pypy/module/micronumpy/ctors.py @@ -2,6 +2,7 @@ from pypy.interpreter.gateway import unwrap_spec, WrappedDefault from rpython.rlib.buffer import SubBuffer from rpython.rlib.rstring import strip_spaces +from rpython.rlib.rawstorage import RAW_STORAGE_PTR from rpython.rtyper.lltypesystem import lltype, rffi from pypy.module.micronumpy import descriptor, loop, support @@ -45,7 +46,7 @@ try: w_interface = space.getattr(w_object, space.wrap("__array_interface__")) if w_interface is None: - return None + return None, False version_w = space.finditem(w_interface, space.wrap("version")) if version_w is None: raise oefmt(space.w_ValueError, "__array_interface__ found without" @@ -67,19 +68,46 @@ raise oefmt(space.w_ValueError, "__array_interface__ missing one or more required keys: shape, typestr" ) - raise oefmt(space.w_NotImplementedError, - "creating array from __array_interface__ not supported yet") - ''' - data_w = space.listview() + if w_descr is not None: + raise oefmt(space.w_NotImplementedError, + "__array_interface__ descr not supported yet") + if w_strides is None or space.is_w(w_strides, space.w_None): + strides = None + else: + strides = [space.int_w(i) for i in space.listview(w_strides)] shape = [space.int_w(i) for i in space.listview(w_shape)] dtype = descriptor.decode_w_dtype(space, w_dtype) - rw = space.is_true(data_w[1]) - ''' - #print 'create view from shape',shape,'dtype',dtype,'descr',w_descr,'data',data_w[0],'rw',rw - return None + if dtype is None: + raise oefmt(space.w_ValueError, + "__array_interface__ could not decode dtype %R", w_dtype + ) + if w_data is not None and (space.isinstance_w(w_data, space.w_tuple) or space.isinstance_w(w_data, space.w_list)): + data_w = space.listview(w_data) + data = rffi.cast(RAW_STORAGE_PTR, space.int_w(data_w[0])) + read_only = True # XXX why not space.is_true(data_w[1]) + offset = 0 + return W_NDimArray.from_shape_and_storage(space, shape, data, + dtype, strides=strides, start=offset), read_only + if w_data is None: + data = w_object + else: + data = w_data + w_offset = space.finditem(w_interface, space.wrap('offset')) + if w_offset is None: + offset = 0 + else: + offset = space.int_w(w_offset) + #print 'create view from shape',shape,'dtype',dtype,'data',data + if strides is not None: + raise oefmt(space.w_NotImplementedError, + "__array_interface__ strides not fully supported yet") + arr = frombuffer(space, data, dtype, support.product(shape), offset) + new_impl = arr.implementation.reshape(arr, shape) + return W_NDimArray(new_impl), False + except OperationError as e: if e.match(space, space.w_AttributeError): - return None + return None, False raise @@ -103,19 +131,20 @@ if space.isinstance_w(w_object, space.w_type): raise oefmt(space.w_ValueError, "cannot create ndarray from type instance") # for anything that isn't already an array, try __array__ method first + dtype = descriptor.decode_w_dtype(space, w_dtype) if not isinstance(w_object, W_NDimArray): w_array = try_array_method(space, w_object, w_dtype) if w_array is not None: # continue with w_array, but do further operations in place w_object = w_array copy = False + dtype = w_object.get_dtype() if not isinstance(w_object, W_NDimArray): - w_array = try_interface_method(space, w_object) + w_array, _copy = try_interface_method(space, w_object) if w_array is not None: w_object = w_array - copy = False - dtype = descriptor.decode_w_dtype(space, w_dtype) - + copy = _copy + dtype = w_object.get_dtype() if isinstance(w_object, W_NDimArray): npy_order = order_converter(space, w_order, NPY.ANYORDER) diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -534,10 +534,10 @@ while not inner_iter.done(inner_state): arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype) w_val = inner_iter.getitem(inner_state) - new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val) - if dtype.itemtype.ne(new_best, cur_best): + old_best = getattr(dtype.itemtype, op_name)(cur_best, w_val) + if not old_best: result = idx - cur_best = new_best + cur_best = w_val inner_state = inner_iter.next(inner_state) idx += 1 result = get_dtype_cache(space).w_longdtype.box(result) @@ -557,17 +557,17 @@ while not iter.done(state): arg_flat_driver.jit_merge_point(shapelen=shapelen, dtype=dtype) w_val = iter.getitem(state) - new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val) - if dtype.itemtype.ne(new_best, cur_best): + old_best = getattr(dtype.itemtype, op_name)(cur_best, w_val) + if not old_best: result = idx - cur_best = new_best + cur_best = w_val state = iter.next(state) idx += 1 return result return argmin_argmax, argmin_argmax_flat -argmin, argmin_flat = _new_argmin_argmax('min') -argmax, argmax_flat = _new_argmin_argmax('max') +argmin, argmin_flat = _new_argmin_argmax('argmin') +argmax, argmax_flat = _new_argmin_argmax('argmax') dot_driver = jit.JitDriver(name = 'numpy_dot', greens = ['dtype'], @@ -684,8 +684,9 @@ arr_iter, arr_state = arr.create_iter() arr_dtype = arr.get_dtype() index_dtype = index.get_dtype() - # XXX length of shape of index as well? - while not index_iter.done(index_state): + # support the deprecated form where arr([True]) will return arr[0, ...] + # by iterating over res_iter, not index_iter + while not res_iter.done(res_state): getitem_filter_driver.jit_merge_point(shapelen=shapelen, index_dtype=index_dtype, arr_dtype=arr_dtype, diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -1852,6 +1852,24 @@ a = array([(1, 2)], dtype=[('a', 'int64'), ('b', 'int64')]) assert a.view('S16')[0] == '\x01' + '\x00' * 7 + '\x02' + def test_half_conversions(self): + from numpy import array, arange + from math import isnan, isinf + e = array([0, -1, -float('inf'), float('nan'), 6], dtype='float16') + assert map(isnan, e) == [False, False, False, True, False] + assert map(isinf, e) == [False, False, True, False, False] + assert e.argmax() == 3 + # numpy preserves value for uint16 -> cast_as_float16 -> + # convert_to_float64 -> convert_to_float16 -> uint16 + # even for float16 various float16 nans + all_f16 = arange(0xfe00, 0xffff, dtype='uint16') + all_f16.dtype = 'float16' + all_f32 = array(all_f16, dtype='float32') + b = array(all_f32, dtype='float16') + c = b.view(dtype='uint16') + d = all_f16.view(dtype='uint16') + assert (c == d).all() + def test_ndarray_view_empty(self): from numpy import array, dtype x = array([], dtype=[('a', 'int8'), ('b', 'int8')]) @@ -2220,6 +2238,9 @@ c = array([True,False,True],bool) b = a[c] assert (a[c] == [[1, 2, 3], [7, 8, 9]]).all() + c = array([True]) + b = a[c] + assert b.shape == (1, 3) def test_bool_array_index_setitem(self): from numpy import arange, array @@ -3052,7 +3073,7 @@ assert (b == zeros(10)).all() def test_array_interface(self): - from numpy import array + from numpy import array, ones a = array(2.5) i = a.__array_interface__ assert isinstance(i['data'][0], int) @@ -3075,7 +3096,7 @@ class Dummy(object): def __init__(self, aif=None): - if aif: + if aif is not None: self.__array_interface__ = aif a = array(Dummy()) @@ -3084,6 +3105,31 @@ raises(ValueError, array, Dummy({'version': 0})) raises(ValueError, array, Dummy({'version': 'abc'})) raises(ValueError, array, Dummy({'version': 3})) + raises(TypeError, array, Dummy({'version': 3, 'typestr': 'f8', 'shape': ('a', 3)})) + + a = array([1, 2, 3]) + b = array(Dummy(a.__array_interface__)) + b[1] = 200 + assert a[1] == 2 # upstream compatibility, is this a bug? + interface_a = a.__array_interface__ + interface_b = b.__array_interface__ + # only the data[0] value should differ + assert interface_a['data'][0] != interface_b['data'][0] + assert interface_b['data'][1] == interface_a['data'][1] + interface_b.pop('data') + interface_a.pop('data') + assert interface_a == interface_b + + b = array(Dummy({'version':3, 'shape': (50,), 'typestr': 'u1', + 'data': 'a'*100})) + assert b.dtype == 'uint8' + assert b.shape == (50,) + + a = ones((1,), dtype='float16') + b = Dummy(a.__array_interface__) + c = array(b) + assert c.dtype == 'float16' + assert (a == c).all() def test_array_indexing_one_elem(self): from numpy import array, arange diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -345,6 +345,14 @@ def min(self, v1, v2): return min(v1, v2) + @raw_binary_op + def argmax(self, v1, v2): + return v1 >= v2 + + @raw_binary_op + def argmin(self, v1, v2): + return v1 <= v2 + @raw_unary_op def rint(self, v): float64 = Float64(self.space) @@ -820,6 +828,14 @@ def min(self, v1, v2): return v1 if v1 <= v2 or rfloat.isnan(v1) else v2 + @raw_binary_op + def argmax(self, v1, v2): + return v1 >= v2 or rfloat.isnan(v1) + + @raw_binary_op + def argmin(self, v1, v2): + return v1 <= v2 or rfloat.isnan(v1) + @simple_binary_op def fmax(self, v1, v2): return v1 if v1 >= v2 or rfloat.isnan(v2) else v2 @@ -1407,6 +1423,16 @@ return v1 return v2 + def argmin(self, v1, v2): + if self.le(v1, v2) or self.isnan(v1): + return True + return False + + def argmax(self, v1, v2): + if self.ge(v1, v2) or self.isnan(v1): + return True + return False + @complex_binary_op def floordiv(self, v1, v2): (r1, i1), (r2, i2) = v1, v2 @@ -1927,6 +1953,18 @@ return v1 return v2 + @raw_binary_op + def argmax(self, v1, v2): + if self.space.is_true(self.space.ge(v1, v2)): + return True + return False + + @raw_binary_op + def argmin(self, v1, v2): + if self.space.is_true(self.space.le(v1, v2)): + return True + return False + @raw_unary_op def bool(self,v): return self._obool(v) diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -248,3 +248,23 @@ loop, = log.loops_by_filename(self.filepath) ops = loop.ops_by_id('getitem', include_guard_not_invalidated=False) assert log.opnames(ops) == [] + + def test_enumerate_list(self): + def main(n): + for a, b in enumerate([1, 2] * 1000): + a + b + + log = self.run(main, [1000]) + loop, = log.loops_by_filename(self.filepath) + opnames = log.opnames(loop.allops()) + assert opnames.count('new_with_vtable') == 0 + + def test_enumerate(self): + def main(n): + for a, b in enumerate("abc" * 1000): + a + ord(b) + + log = self.run(main, [1000]) + loop, = log.loops_by_filename(self.filepath) + opnames = log.opnames(loop.allops()) + assert opnames.count('new_with_vtable') == 0 diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py @@ -1336,7 +1336,8 @@ # these depend on user-defined data, so should not be shared assert ffi1.typeof("struct foo") is not ffi2.typeof("struct foo") assert ffi1.typeof("union foo *") is not ffi2.typeof("union foo*") - assert ffi1.typeof("enum foo") is not ffi2.typeof("enum foo") + # the following test is an opaque enum, which we no longer support + #assert ffi1.typeof("enum foo") is not ffi2.typeof("enum foo") # sanity check: twice 'ffi1' assert ffi1.typeof("struct foo*") is ffi1.typeof("struct foo *") @@ -1348,6 +1349,17 @@ assert ffi.getctype("pe") == 'e *' assert ffi.getctype("e1*") == 'e1 *' + def test_opaque_enum(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef("enum foo;") + from cffi import __version_info__ + if __version_info__ < (1, 4): + py.test.skip("re-enable me in version 1.4") + e = py.test.raises(CDefError, ffi.cast, "enum foo", -1) + assert str(e.value) == ( + "'enum foo' has no values explicitly defined: refusing to guess " + "which integer type it is meant to be (unsigned/signed, int/long)") + def test_new_ctype(self): ffi = FFI(backend=self.Backend()) p = ffi.new("int *") diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_commontypes.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_commontypes.py new file mode 100644 --- /dev/null +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_commontypes.py @@ -0,0 +1,35 @@ +# Generated by pypy/tool/import_cffi.py +import py, os, cffi, re +import _cffi_backend + + +def getlines(): + try: + f = open(os.path.join(os.path.dirname(cffi.__file__), + '..', 'c', 'commontypes.c')) + except IOError: + py.test.skip("cannot find ../c/commontypes.c") + lines = [line for line in f.readlines() if line.strip().startswith('EQ(')] + f.close() + return lines + +def test_alphabetical_order(): + lines = getlines() + assert lines == sorted(lines) + +def test_dependencies(): + r = re.compile(r'EQ[(]"([^"]+)",(?:\s*"([A-Z0-9_]+)\s*[*]*"[)])?') + lines = getlines() + d = {} + for line in lines: + match = r.search(line) + if match is not None: + d[match.group(1)] = match.group(2) + for value in d.values(): + if value: + assert value in d + +def test_get_common_types(): + d = {} + _cffi_backend._get_common_types(d) + assert d["bool"] == "_Bool" 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 @@ -1231,6 +1231,21 @@ def setitem(self, index, char): self.data[index] = char + def getslice(self, start, stop, step, size): + if size == 0: + return "" + if step == 1: + assert 0 <= start <= stop + if start == 0 and stop == len(self.data): + return "".join(self.data) + return "".join(self.data[start:stop]) + return Buffer.getslice(self, start, stop, step, size) + + def setslice(self, start, string): + # No bounds checks. + for i in range(len(string)): + self.data[start + i] = string[i] + @specialize.argtype(1) def _memcmp(selfvalue, buffer, length): diff --git a/pypy/objspace/std/test/test_tupleobject.py b/pypy/objspace/std/test/test_tupleobject.py --- a/pypy/objspace/std/test/test_tupleobject.py +++ b/pypy/objspace/std/test/test_tupleobject.py @@ -413,8 +413,9 @@ from __pypy__ import specialized_zip_2_lists except ImportError: specialized_zip_2_lists = zip - raises(TypeError, specialized_zip_2_lists, [], ()) - raises(TypeError, specialized_zip_2_lists, (), []) + else: + raises(TypeError, specialized_zip_2_lists, [], ()) + raises(TypeError, specialized_zip_2_lists, (), []) assert specialized_zip_2_lists([], []) == [ ] assert specialized_zip_2_lists([2, 3], []) == [ diff --git a/pypy/tool/ann_override.py b/pypy/tool/ann_override.py --- a/pypy/tool/ann_override.py +++ b/pypy/tool/ann_override.py @@ -2,6 +2,7 @@ from rpython.annotator.policy import AnnotatorPolicy from rpython.flowspace.model import Constant from rpython.annotator import specialize +from rpython.annotator.classdesc import InstanceSource, ClassDef @@ -20,7 +21,6 @@ def specialize__wrap(self, funcdesc, args_s): from pypy.interpreter.baseobjspace import W_Root - from rpython.annotator.classdef import ClassDef W_Root_def = funcdesc.bookkeeper.getuniqueclassdef(W_Root) typ = args_s[1].knowntype if isinstance(typ, ClassDef): @@ -50,54 +50,34 @@ typ = (None, str) return funcdesc.cachedgraph(typ) - def _remember_immutable(self, t, cached): - # for jit benefit - if cached not in t._immutable_fields_: # accessed this way just - # for convenience - t._immutable_fields_.append(cached) - - def attach_lookup(self, t, attr): - cached = "cached_%s" % attr - if not t.is_heaptype() and not t.is_cpytype(): - self._remember_immutable(t, cached) - setattr(t, cached, t._lookup(attr)) - return True - return False - - def attach_lookup_in_type_where(self, t, attr): - cached = "cached_where_%s" % attr - if not t.is_heaptype() and not t.is_cpytype(): - self._remember_immutable(t, cached) - setattr(t, cached, t._lookup_where(attr)) - return True - return False - def consider_lookup(self, bookkeeper, attr): - from rpython.annotator.classdef import InstanceSource assert attr not in self.lookups from pypy.objspace.std import typeobject cached = "cached_%s" % attr clsdef = bookkeeper.getuniqueclassdef(typeobject.W_TypeObject) classdesc = clsdef.classdesc + classdesc.immutable_fields.add(cached) classdesc.classdict[cached] = Constant(None) clsdef.add_source_for_attribute(cached, classdesc) for t in self.pypytypes: - if self.attach_lookup(t, attr): + if not (t.is_heaptype() or t.is_cpytype()): + setattr(t, cached, t._lookup(attr)) source = InstanceSource(bookkeeper, t) clsdef.add_source_for_attribute(cached, source) self.lookups[attr] = True def consider_lookup_in_type_where(self, bookkeeper, attr): - from rpython.annotator.classdef import InstanceSource assert attr not in self.lookups_where from pypy.objspace.std import typeobject cached = "cached_where_%s" % attr clsdef = bookkeeper.getuniqueclassdef(typeobject.W_TypeObject) classdesc = clsdef.classdesc + classdesc.immutable_fields.add(cached) classdesc.classdict[cached] = Constant((None, None)) clsdef.add_source_for_attribute(cached, classdesc) for t in self.pypytypes: - if self.attach_lookup_in_type_where(t, attr): + if not (t.is_heaptype() or t.is_cpytype()): + setattr(t, cached, t._lookup_where(attr)) source = InstanceSource(bookkeeper, t) clsdef.add_source_for_attribute(cached, source) self.lookups_where[attr] = True @@ -135,18 +115,19 @@ def event(self, bookkeeper, what, x): from pypy.objspace.std import typeobject if isinstance(x, typeobject.W_TypeObject): - from rpython.annotator.classdef import InstanceSource clsdef = bookkeeper.getuniqueclassdef(typeobject.W_TypeObject) self.pypytypes[x] = True #print "TYPE", x for attr in self.lookups: - if attr and self.attach_lookup(x, attr): + if attr and not (x.is_heaptype() or x.is_cpytype()): cached = "cached_%s" % attr + setattr(x, cached, x._lookup(attr)) source = InstanceSource(bookkeeper, x) clsdef.add_source_for_attribute(cached, source) for attr in self.lookups_where: - if attr and self.attach_lookup_in_type_where(x, attr): + if attr and not (x.is_heaptype() or x.is_cpytype()): cached = "cached_where_%s" % attr + setattr(x, cached, x._lookup_where(attr)) source = InstanceSource(bookkeeper, x) clsdef.add_source_for_attribute(cached, source) return diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py --- a/rpython/annotator/bookkeeper.py +++ b/rpython/annotator/bookkeeper.py @@ -14,8 +14,8 @@ SomeDict, SomeBuiltin, SomePBC, SomeInteger, TLS, SomeUnicodeCodePoint, s_None, s_ImpossibleValue, SomeBool, SomeTuple, SomeImpossibleValue, SomeUnicodeString, SomeList, HarmlesslyBlocked, - SomeWeakRef, SomeByteArray, SomeConstantType, SomeProperty, AnnotatorError) -from rpython.annotator.classdef import InstanceSource, ClassDef + SomeWeakRef, SomeByteArray, SomeConstantType, SomeProperty) +from rpython.annotator.classdesc import ClassDef, ClassDesc from rpython.annotator.listdef import ListDef, ListItem from rpython.annotator.dictdef import DictDef from rpython.annotator import description @@ -23,7 +23,6 @@ from rpython.annotator.argument import simple_args from rpython.rlib.objectmodel import r_dict, r_ordereddict, Symbolic from rpython.tool.algo.unionfind import UnionFind -from rpython.tool.flattenrec import FlattenRecursion from rpython.rtyper import extregistry @@ -163,9 +162,7 @@ s_callable.consider_call_site(args, s_result, call_op) def getuniqueclassdef(self, cls): - """Get the ClassDef associated with the given user cls. - Avoid using this! It breaks for classes that must be specialized. - """ + """Get the ClassDef associated with the given user cls.""" assert cls is not object desc = self.getdesc(cls) return desc.getuniqueclassdef() @@ -334,8 +331,9 @@ and x.__class__.__module__ != '__builtin__': if hasattr(x, '_cleanup_'): x._cleanup_() - self.see_mutable(x) - result = SomeInstance(self.getuniqueclassdef(x.__class__)) + classdef = self.getuniqueclassdef(x.__class__) + classdef.see_instance(x) + result = SomeInstance(classdef) elif x is None: return s_None else: @@ -362,7 +360,7 @@ if pyobj.__module__ == '__builtin__': # avoid making classdefs for builtin types result = self.getfrozen(pyobj) else: - result = description.ClassDesc(self, pyobj) + result = ClassDesc(self, pyobj) elif isinstance(pyobj, types.MethodType): if pyobj.im_self is None: # unbound return self.getdesc(pyobj.im_func) @@ -375,11 +373,11 @@ self.getdesc(pyobj.im_self)) # frozendesc else: # regular method origincls, name = origin_of_meth(pyobj) - self.see_mutable(pyobj.im_self) + classdef = self.getuniqueclassdef(pyobj.im_class) + classdef.see_instance(pyobj.im_self) assert pyobj == getattr(pyobj.im_self, name), ( "%r is not %s.%s ??" % (pyobj, pyobj.im_self, name)) # emulate a getattr to make sure it's on the classdef - classdef = self.getuniqueclassdef(pyobj.im_class) classdef.find_attribute(name) result = self.getmethoddesc( self.getdesc(pyobj.im_func), # funcdesc @@ -400,15 +398,6 @@ self.descs[pyobj] = result return result - def have_seen(self, x): - # this might need to expand some more. - if x in self.descs: - return True - elif (x.__class__, x) in self.seen_mutable: - return True - else: - return False - def getfrozen(self, pyobj): return description.FrozenDesc(self, pyobj) @@ -425,22 +414,6 @@ self.methoddescs[key] = result return result - _see_mutable_flattenrec = FlattenRecursion() - - def see_mutable(self, x): - key = (x.__class__, x) - if key in self.seen_mutable: - return - clsdef = self.getuniqueclassdef(x.__class__) - self.seen_mutable[key] = True - self.event('mutable', x) - source = InstanceSource(self, x) - def delayed(): - for attr in source.all_instance_attributes(): - clsdef.add_source_for_attribute(attr, source) - # ^^^ can trigger reflowing - self._see_mutable_flattenrec(delayed) - def valueoftype(self, t): return annotationoftype(t, self) @@ -495,6 +468,20 @@ return s_result + def getattr_locations(self, clsdesc, attrname): + attrdef = clsdesc.classdef.find_attribute(attrname) + return attrdef.read_locations + + def record_getattr(self, clsdesc, attrname): + locations = self.getattr_locations(clsdesc, attrname) + locations.add(self.position_key) + + def update_attr(self, clsdef, attrdef): + locations = self.getattr_locations(clsdef.classdesc, attrdef.name) + for position in locations: + self.annotator.reflowfromposition(position) + attrdef.validate(homedef=clsdef) + def pbc_call(self, pbc, args, emulated=None): """Analyse a call to a SomePBC() with the given args (list of annotations). diff --git a/rpython/annotator/builtin.py b/rpython/annotator/builtin.py --- a/rpython/annotator/builtin.py +++ b/rpython/annotator/builtin.py @@ -5,13 +5,14 @@ from collections import OrderedDict from rpython.annotator.model import ( - SomeInteger, SomeObject, SomeChar, SomeBool, SomeString, SomeTuple, + SomeInteger, SomeChar, SomeBool, SomeString, SomeTuple, SomeUnicodeCodePoint, SomeFloat, unionof, SomeUnicodeString, SomePBC, SomeInstance, SomeDict, SomeList, SomeWeakRef, SomeIterator, SomeOrderedDict, SomeByteArray, add_knowntypedata, s_ImpossibleValue,) from rpython.annotator.bookkeeper import ( getbookkeeper, immutablevalue, BUILTIN_ANALYZERS, analyzer_for) from rpython.annotator import description +from rpython.annotator.classdesc import ClassDef from rpython.flowspace.model import Constant import rpython.rlib.rarithmetic import rpython.rlib.objectmodel @@ -124,7 +125,6 @@ def our_issubclass(cls1, cls2): """ we're going to try to be less silly in the face of old-style classes""" - from rpython.annotator.classdef import ClassDef if cls2 is object: return True def classify(cls): diff --git a/rpython/annotator/classdef.py b/rpython/annotator/classdef.py deleted file mode 100644 --- a/rpython/annotator/classdef.py +++ /dev/null @@ -1,434 +0,0 @@ -""" -Type inference for user-defined classes. -""" -from rpython.annotator.model import ( - SomePBC, s_ImpossibleValue, unionof, s_None, AnnotatorError) -from rpython.annotator import description - - -# The main purpose of a ClassDef is to collect information about class/instance -# attributes as they are really used. An Attribute object is stored in the -# most general ClassDef where an attribute of that name is read/written: -# classdef.attrs = {'attrname': Attribute()} -# -# The following invariants hold: -# -# (A) if an attribute is read/written on an instance of class A, then the -# classdef of A or a parent class of A has an Attribute object corresponding -# to that name. -# -# (I) if B is a subclass of A, then they don't both have an Attribute for the -# same name. (All information from B's Attribute must be merged into A's.) -# -# Additionally, each ClassDef records an 'attr_sources': it maps attribute names -# to a list of 'source' objects that want to provide a constant value for this -# attribute at the level of this class. The attr_sources provide information -# higher in the class hierarchy than concrete Attribute()s. It is for the case -# where (so far or definitely) the user program only reads/writes the attribute -# at the level of a subclass, but a value for this attribute could possibly -# exist in the parent class or in an instance of a parent class. -# -# The point of not automatically forcing the Attribute instance up to the -# parent class which has a class attribute of the same name is apparent with -# multiple subclasses: -# -# A -# attr=s1 -# / \ -# / \ -# B C -# attr=s2 attr=s3 -# -# XXX this does not seem to be correct, but I don't know how to phrase -# it correctly. See test_specific_attributes in test_annrpython -# -# In this case, as long as 'attr' is only read/written from B or C, the -# Attribute on B says that it can be 's1 or s2', and the Attribute on C says -# it can be 's1 or s3'. Merging them into a single Attribute on A would give -# the more imprecise 's1 or s2 or s3'. -# -# The following invariant holds: -# -# (II) if a class A has an Attribute, the 'attr_sources' for the same name is -# empty. It is also empty on all subclasses of A. (The information goes -# into the Attribute directly in this case.) -# -# The following invariant holds: -# -# (III) for a class A, each attrsource that comes from the class (as opposed to -# from a prebuilt instance) must be merged into all Attributes of the -# same name in all subclasses of A, if any. (Parent class attributes can -# be visible in reads from instances of subclasses.) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit