Author: Ronan Lamy <ronan.l...@gmail.com> Branch: py3.5 Changeset: r91477:776f5fd5d727 Date: 2017-05-31 22:32 +0100 http://bitbucket.org/pypy/pypy/changeset/776f5fd5d727/
Log: hg merge default diff too long, truncating to 2000 out of 2270 lines diff --git a/lib-python/2.7/ctypes/test/test_unaligned_structures.py b/lib-python/2.7/ctypes/test/test_unaligned_structures.py --- a/lib-python/2.7/ctypes/test/test_unaligned_structures.py +++ b/lib-python/2.7/ctypes/test/test_unaligned_structures.py @@ -37,7 +37,10 @@ for typ in byteswapped_structures: ## print >> sys.stderr, typ.value self.assertEqual(typ.value.offset, 1) - o = typ() + try: + o = typ() + except NotImplementedError as e: + self.skipTest(str(e)) # for PyPy o.value = 4 self.assertEqual(o.value, 4) diff --git a/lib-python/2.7/zipfile.py b/lib-python/2.7/zipfile.py --- a/lib-python/2.7/zipfile.py +++ b/lib-python/2.7/zipfile.py @@ -622,19 +622,23 @@ """Read and return up to n bytes. If the argument is omitted, None, or negative, data is read and returned until EOF is reached.. """ - buf = '' + # PyPy modification: don't do repeated string concatenation + buf = [] + lenbuf = 0 if n is None: n = -1 while True: if n < 0: data = self.read1(n) - elif n > len(buf): - data = self.read1(n - len(buf)) + elif n > lenbuf: + data = self.read1(n - lenbuf) else: - return buf + break if len(data) == 0: - return buf - buf += data + break + lenbuf += len(data) + buf.append(data) + return "".join(buf) def _update_crc(self, newdata, eof): # Update the CRC using the given data. 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.10.0 +Version: 1.11.0 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 from .error import CDefError, FFIError, VerificationError, VerificationMissing -__version__ = "1.10.0" -__version_info__ = (1, 10, 0) +__version__ = "1.11.0" +__version_info__ = (1, 11, 0) # 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/_cffi_include.h b/lib_pypy/cffi/_cffi_include.h --- a/lib_pypy/cffi/_cffi_include.h +++ b/lib_pypy/cffi/_cffi_include.h @@ -8,7 +8,7 @@ the same works for the other two macros. Py_DEBUG implies them, but not the other way around. */ -#ifndef _CFFI_USE_EMBEDDING +#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) # include <pyconfig.h> # if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) # define Py_LIMITED_API diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h --- a/lib_pypy/cffi/_embedding.h +++ b/lib_pypy/cffi/_embedding.h @@ -233,7 +233,7 @@ f = PySys_GetObject((char *)"stderr"); if (f != NULL && f != Py_None) { PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME - "\ncompiled with cffi version: 1.10.0" + "\ncompiled with cffi version: 1.11.0" "\n_cffi_backend module: ", f); modules = PyImport_GetModuleDict(); mod = PyDict_GetItemString(modules, "_cffi_backend"); diff --git a/lib_pypy/cffi/cffi_opcode.py b/lib_pypy/cffi/cffi_opcode.py --- a/lib_pypy/cffi/cffi_opcode.py +++ b/lib_pypy/cffi/cffi_opcode.py @@ -105,8 +105,11 @@ PRIM_UINT_FAST64 = 45 PRIM_INTMAX = 46 PRIM_UINTMAX = 47 +PRIM_FLOATCOMPLEX = 48 +PRIM_DOUBLECOMPLEX = 49 -_NUM_PRIM = 48 + +_NUM_PRIM = 50 _UNKNOWN_PRIM = -1 _UNKNOWN_FLOAT_PRIM = -2 _UNKNOWN_LONG_DOUBLE = -3 @@ -128,6 +131,8 @@ 'float': PRIM_FLOAT, 'double': PRIM_DOUBLE, 'long double': PRIM_LONGDOUBLE, + 'float _Complex': PRIM_FLOATCOMPLEX, + 'double _Complex': PRIM_DOUBLECOMPLEX, '_Bool': PRIM_BOOL, 'wchar_t': PRIM_WCHAR, 'int8_t': PRIM_INT8, 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 @@ -16,6 +16,7 @@ except ImportError: lock = None +CDEF_SOURCE_STRING = "<cdef source string>" _r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", re.DOTALL | re.MULTILINE) _r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" @@ -258,15 +259,21 @@ ctn.discard(name) typenames += sorted(ctn) # - csourcelines = ['typedef int %s;' % typename for typename in typenames] + csourcelines = [] + csourcelines.append('# 1 "<cdef automatic initialization code>"') + for typename in typenames: + csourcelines.append('typedef int %s;' % typename) csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,' ' __dotdotdot__;') + # this forces pycparser to consider the following in the file + # called <cdef source string> from line 1 + csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,)) csourcelines.append(csource) - csource = '\n'.join(csourcelines) + fullcsource = '\n'.join(csourcelines) if lock is not None: lock.acquire() # pycparser is not thread-safe... try: - ast = _get_parser().parse(csource) + ast = _get_parser().parse(fullcsource) except pycparser.c_parser.ParseError as e: self.convert_pycparser_error(e, csource) finally: @@ -276,17 +283,17 @@ return ast, macros, csource def _convert_pycparser_error(self, e, csource): - # xxx look for ":NUM:" at the start of str(e) and try to interpret - # it as a line number + # xxx look for "<cdef source string>:NUM:" at the start of str(e) + # and interpret that as a line number. This will not work if + # the user gives explicit ``# NUM "FILE"`` directives. line = None msg = str(e) - if msg.startswith(':') and ':' in msg[1:]: - linenum = msg[1:msg.find(':',1)] - if linenum.isdigit(): - linenum = int(linenum, 10) - csourcelines = csource.splitlines() - if 1 <= linenum <= len(csourcelines): - line = csourcelines[linenum-1] + match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg) + if match: + linenum = int(match.group(1), 10) + csourcelines = csource.splitlines() + if 1 <= linenum <= len(csourcelines): + line = csourcelines[linenum-1] return line def convert_pycparser_error(self, e, csource): @@ -321,10 +328,12 @@ break else: assert 0 + current_decl = None # try: self._inside_extern_python = '__cffi_extern_python_stop' for decl in iterator: + current_decl = decl if isinstance(decl, pycparser.c_ast.Decl): self._parse_decl(decl) elif isinstance(decl, pycparser.c_ast.Typedef): @@ -348,7 +357,13 @@ elif decl.__class__.__name__ == 'Pragma': pass # skip pragma, only in pycparser 2.15 else: - raise CDefError("unrecognized construct", decl) + raise CDefError("unexpected <%s>: this construct is valid " + "C but not valid in cdef()" % + decl.__class__.__name__, decl) + except CDefError as e: + if len(e.args) == 1: + e.args = e.args + (current_decl,) + raise except FFIError as e: msg = self._convert_pycparser_error(e, csource) if msg: diff --git a/lib_pypy/cffi/error.py b/lib_pypy/cffi/error.py --- a/lib_pypy/cffi/error.py +++ b/lib_pypy/cffi/error.py @@ -5,10 +5,13 @@ class CDefError(Exception): def __str__(self): try: - line = 'line %d: ' % (self.args[1].coord.line,) + current_decl = self.args[1] + filename = current_decl.coord.file + linenum = current_decl.coord.line + prefix = '%s:%d: ' % (filename, linenum) except (AttributeError, TypeError, IndexError): - line = '' - return '%s%s' % (line, self.args[0]) + prefix = '' + return '%s%s' % (prefix, self.args[0]) class VerificationError(Exception): """ An error raised when verification fails diff --git a/lib_pypy/cffi/ffiplatform.py b/lib_pypy/cffi/ffiplatform.py --- a/lib_pypy/cffi/ffiplatform.py +++ b/lib_pypy/cffi/ffiplatform.py @@ -6,6 +6,7 @@ 'extra_objects', 'depends'] def get_extension(srcfilename, modname, sources=(), **kwds): + _hack_at_distutils() from distutils.core import Extension allsources = [srcfilename] for src in sources: @@ -15,6 +16,7 @@ def compile(tmpdir, ext, compiler_verbose=0, debug=None): """Compile a C extension module using distutils.""" + _hack_at_distutils() saved_environ = os.environ.copy() try: outputfilename = _build(tmpdir, ext, compiler_verbose, debug) @@ -113,3 +115,13 @@ f = cStringIO.StringIO() _flatten(x, f) return f.getvalue() + +def _hack_at_distutils(): + # Windows-only workaround for some configurations: see + # https://bugs.python.org/issue23246 (Python 2.7 with + # a specific MS compiler suite download) + if sys.platform == "win32": + try: + import setuptools # for side-effects, patches distutils + except ImportError: + pass 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 @@ -95,7 +95,8 @@ class BasePrimitiveType(BaseType): - pass + def is_complex_type(self): + return False class PrimitiveType(BasePrimitiveType): @@ -116,6 +117,8 @@ 'float': 'f', 'double': 'f', 'long double': 'f', + 'float _Complex': 'j', + 'double _Complex': 'j', '_Bool': 'i', # the following types are not primitive in the C sense 'wchar_t': 'c', @@ -163,6 +166,8 @@ return self.ALL_PRIMITIVE_TYPES[self.name] == 'i' def is_float_type(self): return self.ALL_PRIMITIVE_TYPES[self.name] == 'f' + def is_complex_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'j' def build_backend_type(self, ffi, finishlist): return global_cache(self, ffi, 'new_primitive_type', self.name) diff --git a/lib_pypy/cffi/parse_c_type.h b/lib_pypy/cffi/parse_c_type.h --- a/lib_pypy/cffi/parse_c_type.h +++ b/lib_pypy/cffi/parse_c_type.h @@ -79,8 +79,10 @@ #define _CFFI_PRIM_UINT_FAST64 45 #define _CFFI_PRIM_INTMAX 46 #define _CFFI_PRIM_UINTMAX 47 +#define _CFFI_PRIM_FLOATCOMPLEX 48 +#define _CFFI_PRIM_DOUBLECOMPLEX 49 -#define _CFFI__NUM_PRIM 48 +#define _CFFI__NUM_PRIM 50 #define _CFFI__UNKNOWN_PRIM (-1) #define _CFFI__UNKNOWN_FLOAT_PRIM (-2) #define _CFFI__UNKNOWN_LONG_DOUBLE (-3) diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py --- a/lib_pypy/cffi/recompiler.py +++ b/lib_pypy/cffi/recompiler.py @@ -506,7 +506,7 @@ def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): extraarg = '' - if isinstance(tp, model.BasePrimitiveType): + if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): if tp.is_integer_type() and tp.name != '_Bool': converter = '_cffi_to_c_int' extraarg = ', %s' % tp.name @@ -524,8 +524,10 @@ tovar, errcode) return # - elif isinstance(tp, model.StructOrUnionOrEnum): - # a struct (not a struct pointer) as a function argument + elif (isinstance(tp, model.StructOrUnionOrEnum) or + isinstance(tp, model.BasePrimitiveType)): + # a struct (not a struct pointer) as a function argument; + # or, a complex (the same code works) self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' % (tovar, self._gettypenum(tp), fromvar)) self._prnt(' %s;' % errcode) @@ -570,7 +572,7 @@ return '_cffi_from_c_int(%s, %s)' % (var, tp.name) elif isinstance(tp, model.UnknownFloatType): return '_cffi_from_c_double(%s)' % (var,) - elif tp.name != 'long double': + elif tp.name != 'long double' and not tp.is_complex_type(): return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) else: return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( @@ -734,21 +736,26 @@ # # the PyPy version: need to replace struct/union arguments with # pointers, and if the result is a struct/union, insert a first - # arg that is a pointer to the result. + # arg that is a pointer to the result. We also do that for + # complex args and return type. + def need_indirection(type): + return (isinstance(type, model.StructOrUnion) or + (isinstance(type, model.PrimitiveType) and + type.is_complex_type())) difference = False arguments = [] call_arguments = [] context = 'argument of %s' % name for i, type in enumerate(tp.args): indirection = '' - if isinstance(type, model.StructOrUnion): + if need_indirection(type): indirection = '*' difference = True arg = type.get_c_name(' %sx%d' % (indirection, i), context) arguments.append(arg) call_arguments.append('%sx%d' % (indirection, i)) tp_result = tp.result - if isinstance(tp_result, model.StructOrUnion): + if need_indirection(tp_result): context = 'result of %s' % name arg = tp_result.get_c_name(' *result', context) arguments.insert(0, arg) @@ -1180,7 +1187,7 @@ size_of_result = '(int)sizeof(%s)' % ( tp.result.get_c_name('', context),) prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name) - prnt(' { "%s", %s };' % (name, size_of_result)) + prnt(' { "%s.%s", %s };' % (self.module_name, name, size_of_result)) prnt() # arguments = [] @@ -1479,6 +1486,12 @@ _patch_for_embedding(patchlist) if target != '*': _patch_for_target(patchlist, target) + if compiler_verbose: + if tmpdir == '.': + msg = 'the current directory is' + else: + msg = 'setting the current directory to' + print('%s %r' % (msg, os.path.abspath(tmpdir))) os.chdir(tmpdir) outputfilename = ffiplatform.compile('.', ext, compiler_verbose, debug) diff --git a/lib_pypy/cffi/verifier.py b/lib_pypy/cffi/verifier.py --- a/lib_pypy/cffi/verifier.py +++ b/lib_pypy/cffi/verifier.py @@ -26,16 +26,6 @@ s = s.encode('ascii') super(NativeIO, self).write(s) -def _hack_at_distutils(): - # Windows-only workaround for some configurations: see - # https://bugs.python.org/issue23246 (Python 2.7 with - # a specific MS compiler suite download) - if sys.platform == "win32": - try: - import setuptools # for side-effects, patches distutils - except ImportError: - pass - class Verifier(object): @@ -126,7 +116,7 @@ return basename def get_extension(self): - _hack_at_distutils() # backward compatibility hack + ffiplatform._hack_at_distutils() # backward compatibility hack if not self._has_source: with self.ffi._lock: if not self._has_source: diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -364,6 +364,26 @@ .. __: https://bitbucket.org/pypy/pypy/issue/1974/different-behaviour-for-collections-of +C-API Differences +----------------- + +The external C-API has been reimplemented in PyPy as an internal cpyext module. +We support most of the documented C-API, but sometimes internal C-abstractions +leak out on CPython and are abused, perhaps even unknowingly. For instance, +assignment to a ``PyTupleObject`` is not supported after the tuple is +used internally, even by another C-API function call. On CPython this will +succeed as long as the refcount is 1. On PyPy this will always raise a +``SystemError('PyTuple_SetItem called on tuple after use of tuple")`` +exception (explicitly listed here for search engines). + +Another similar problem is assignment of a new function pointer to any of the +``tp_as_*`` structures after calling ``PyType_Ready``. For instance, overriding +``tp_as_number.nb_int`` with a different function after calling ``PyType_Ready`` +on CPython will result in the old function being called for ``x.__int__()`` +(via class ``__dict__`` lookup) and the new function being called for ``int(x)`` +(via slot lookup). On PyPy we will always call the __new__ function, not the +old, this quirky behaviour is unfortunately necessary to fully support NumPy. + Performance Differences ------------------------- diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst --- a/pypy/doc/index-of-release-notes.rst +++ b/pypy/doc/index-of-release-notes.rst @@ -6,6 +6,7 @@ .. toctree:: + release-v5.8.0.rst release-v5.7.1.rst release-v5.7.0.rst release-pypy2.7-v5.6.0.rst @@ -60,6 +61,7 @@ .. toctree:: + release-v5.8.0.rst release-v5.7.1.rst release-v5.7.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-pypy2-5.8.0.rst whatsnew-pypy2-5.7.0.rst whatsnew-pypy2-5.6.0.rst whatsnew-pypy2-5.4.0.rst diff --git a/pypy/doc/release-v5.8.0.rst b/pypy/doc/release-v5.8.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-v5.8.0.rst @@ -0,0 +1,155 @@ +===================================== +PyPy2.7 and PyPy3.5 v5.8 dual release +===================================== + +The PyPy team is proud to release both PyPy2.7 v5.8 (an interpreter supporting +Python v2.7 syntax), and a beta-quality PyPy3.5 v5.8 (an interpreter for Python +v3.5 syntax). The two releases are both based on much the same codebase, thus +the dual release. Note that PyPy3.5 supports Linux 64bit only for now. + +This new PyPy2.7 release includes the upstream stdlib version 2.7.13, and +PyPy3.5 (our first in the 3.5 series) includes the upstream stdlib version +3.5.3. + +We continue to make incremental improvements to our C-API +compatibility layer (cpyext). PyPy2 can now import and run many C-extension +packages, among the most notable are Numpy, Cython, and Pandas. Performance may +be slower than CPython, especially for frequently-called short C functions. +Please let us know if your use case is slow, we have ideas how to make things +faster but need real-world examples (not micro-benchmarks) of problematic code. + +Work proceeds at a good pace on the PyPy3.5 +version due to a grant_ from the Mozilla Foundation, hence our first 3.5.3 beta +release. Thanks Mozilla !!! While we do not pass all tests yet, asyncio works and +as `these benchmarks show`_ it already gives a nice speed bump. +We also backported the ``f""`` formatting from 3.6 (as an exception; otherwise +"PyPy3.5" supports the Python 3.5 language). + +CFFI_ has been updated to 1.10, improving an already great package for +interfacing with C. + +As always, this release fixed many issues and bugs raised by the +growing community of PyPy users. We strongly recommend updating. + +You can download the v5.8 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: https://cffi.readthedocs.io/en/latest/whatsnew.html +.. _grant: https://morepypy.blogspot.com/2016/08/pypy-gets-funding-from-mozilla-for.html +.. _`PyPy`: index.html +.. _`RPython`: https://rpython.readthedocs.org +.. _`modules`: project-ideas.html#make-more-python-modules-pypy-friendly +.. _`help`: project-ideas.html +.. _`these benchmarks show`: https://morepypy.blogspot.com/2017/03/async-http-benchmarks-on-pypy3.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7 and CPython 3.5. It's fast (`PyPy and CPython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +We also welcome developers of other `dynamic languages`_ to see what RPython +can do for them. + +The PyPy 2.7 release supports: + + * **x86** machines on most common operating systems + (Linux 32/64 bits, Mac OS X 64 bits, Windows 32 bits, OpenBSD, FreeBSD) + + * newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux, + + * big- and little-endian variants of **PPC64** running Linux, + + * **s390x** running Linux + +.. _`PyPy and CPython 2.7.x`: http://speed.pypy.org +.. _`dynamic languages`: http://rpython.readthedocs.io/en/latest/examples.html + +Highlights of the PyPy2.7, cpyext, and RPython changes (since 5.7 released March, 2017) +======================================================================================= + +See also issues that were resolved_ + +* New features and cleanups + + * Implement PyModule_New, + * Fix for multiple inheritance in app-level for C-API defined classes + * Revert a change that removed tp_getattr (Part of the 5.7.1 bugfix release) + * Document more differences with CPython here_ + * Add native PyPy support to profile frames in vmprof + * Fix an issue with Exception order on failed import + * Fix for a corner case of __future__ imports + +* Bug Fixes + + * Correctly handle dict.pop where the popping key is not the same type as the + dict's and pop is called with a default (Part of the 5.7.1 bugfix release) + * Improve our file's universal newline .readline implementation for + ``\n``, ``\r`` confusion + +* Performance improvements: + + * Tweaks made to improve performance by reducing the number of guards + inserted in jitted code, based on feedback from users + * Add garbage collector memory pressure to some c-level allocations + +* RPython improvements + + * Improve the default shadowstack garbage collector, fixing a crash with + multithreaded code and other issues + * Make sure lstrip consumes the entire string + * Support posix_fallocate and posix_fadvise, expose them on PyPy3.5 + * Test and fix for int_and() propagating wrong bounds + * Improve the generated machine code by tracking the (constant) value of + r11 across intructions. This lets us avoid reloading r11 with another + (apparently slowish) "movabs" instruction, replacing it with either + nothing or a cheaper variant. + * Performance tweaks in the x86 JIT-generated machine code: rarely taken + blocks are moved off-line. Also, the temporary register used to contain + large constants is reused across instructions. This helps CPUs branch + predictor + +.. _here: http://rpython.readthedocs.io/en/latest/cpython_differences.html + +Highlights of the PyPy3.5 release (since 5.7 beta released March 2017) +====================================================================== + +* New features + + * Implement main part of PEP 489 (multi-phase extension module initialization) + * Add docstrings to various modules and functions + +* Bug Fixes + + * Fix inconsistencies in the xml.etree.ElementTree.Element class, which on + CPython is hidden by the C version from '_elementree'. + * OSError(None,None) is different from OSError() + * Get closer to supporting 32 bit windows, translation now succeeds and most + lib-python/3/test runs + +* Performance improvements: + + * Use "<python> -m test" to run the CPython test suite, as documented by CPython, + instead of our outdated regrverbose.py script + * Change _cffi_src/openssl/callbacks.py to stop relying on the CPython C API. + +* The following features of Python 3.5 are not implemented yet in PyPy: + + * PEP 442: Safe object finalization + +.. _resolved: whatsnew-pypy2-5.8.0.html + +Please update, and continue to help us make PyPy better. + +Cheers 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,70 +1,10 @@ ========================== -What's new in PyPy2.7 5.8+ +What's new in PyPy2.7 5.9+ ========================== -.. this is a revision shortly after release-pypy2.7-v5.7.0 -.. startrev: 44f31f6dd39f +.. this is a revision shortly after release-pypy2.7-v5.8.0 +.. startrev: 558bd00b3dd8 -Add cpyext interfaces for ``PyModule_New`` +.. branch: cffi-complex -Correctly handle `dict.pop`` where the ``pop`` -key is not the same type as the ``dict``'s and ``pop`` -is called with a default (will be part of release 5.7.1) - -.. branch: issue2522 - -Fix missing tp_new on w_object called through multiple inheritance -(will be part of release 5.7.1) - -.. branch: lstrip_to_empty_string - -.. branch: vmprof-native - -PyPy support to profile native frames in vmprof. - -.. branch: reusing-r11 -.. branch: branch-prediction - -Performance tweaks in the x86 JIT-generated machine code: rarely taken -blocks are moved off-line. Also, the temporary register used to contain -large constants is reused across instructions. - -.. branch: vmprof-0.4.4 - -.. branch: controller-refactor - -Refactor rpython.rtyper.controllerentry. - -.. branch: PyBuffer-backport - -Internal refactoring of buffers and memoryviews. Memoryviews will now be -accepted in a few more places, e.g. in compile(). - -.. branch: sthalik/fix-signed-integer-sizes-1494493539409 - -.. branch: cpyext-obj-stealing - -Redo much of the refcount semantics in PyList_{SG}etItem to closer match -CPython and ensure the same PyObject stored in the list can be later -retrieved - -.. branch: cpyext-recursionlimit - -Implement Py_EnterRecursiveCall and associated functions - -.. branch: pypy_ctypes_nosegfault_nofastpath - -Remove faulty fastpath from ctypes - -.. branch: sockopt_zero - -Passing a buffersize of 0 to socket.getsockopt - -.. branch: better-test-whatsnew - -.. branch: faster-rstruct-2 - -Improve the performance of struct.pack and struct.pack_into by using raw_store -or gc_store_indexed whenever possible. Moreover, enable the existing -struct.unpack fast path to all the existing buffer types, whereas previously -it was enabled only for strings +Part of the upgrade to cffi 1.11 diff --git a/pypy/doc/whatsnew-pypy2-5.8.0.rst b/pypy/doc/whatsnew-pypy2-5.8.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/whatsnew-pypy2-5.8.0.rst @@ -0,0 +1,77 @@ +========================== +What's new in PyPy2.7 5.8+ +========================== + +.. this is a revision shortly after release-pypy2.7-v5.7.0 +.. startrev: 44f31f6dd39f + +Add cpyext interfaces for ``PyModule_New`` + +Correctly handle `dict.pop`` where the ``pop`` +key is not the same type as the ``dict``'s and ``pop`` +is called with a default (will be part of release 5.7.1) + +.. branch: issue2522 + +Fix missing tp_new on w_object called through multiple inheritance +(will be part of release 5.7.1) + +.. branch: lstrip_to_empty_string + +.. branch: vmprof-native + +PyPy support to profile native frames in vmprof. + +.. branch: reusing-r11 +.. branch: branch-prediction + +Performance tweaks in the x86 JIT-generated machine code: rarely taken +blocks are moved off-line. Also, the temporary register used to contain +large constants is reused across instructions. + +.. branch: vmprof-0.4.4 + +.. branch: controller-refactor + +Refactor rpython.rtyper.controllerentry. + +.. branch: PyBuffer-backport + +Internal refactoring of buffers and memoryviews. Memoryviews will now be +accepted in a few more places, e.g. in compile(). + +.. branch: sthalik/fix-signed-integer-sizes-1494493539409 + +.. branch: cpyext-obj-stealing + +Redo much of the refcount semantics in PyList_{SG}etItem to closer match +CPython and ensure the same PyObject stored in the list can be later +retrieved + +.. branch: cpyext-recursionlimit + +Implement Py_EnterRecursiveCall and associated functions + +.. branch: pypy_ctypes_nosegfault_nofastpath + +Remove faulty fastpath from ctypes + +.. branch: sockopt_zero + +Passing a buffersize of 0 to socket.getsockopt + +.. branch: better-test-whatsnew + +.. branch: faster-rstruct-2 + +Improve the performance of struct.pack and struct.pack_into by using raw_store +or gc_store_indexed whenever possible. Moreover, enable the existing +struct.unpack fast path to all the existing buffer types, whereas previously +it was enabled only for strings + +.. branch: Kounavi/fix-typo-depricate-to-deprecate-p-1495624547235 + +.. branch: PyPy_profopt_enabled + +Add profile-based optimization option ``profopt``, and specify training data +via ``profoptpath`` diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -810,8 +810,8 @@ '"license" for more information.', file=sys.stderr) STDLIB_WARNING = """\ -debug: WARNING: Library path not found, using compiled-in sys.path. -debug: WARNING: 'sys.prefix' will not be set. +debug: WARNING: Library path not found, using compiled-in sys.path, with +debug: WARNING: sys.prefix = %r debug: WARNING: Make sure the pypy3 binary is kept inside its tree of files. debug: WARNING: It is ok to create a symlink to it from somewhere else.""" @@ -830,13 +830,9 @@ executable = sys.pypy_find_executable(executable) stdlib_path = sys.pypy_find_stdlib(executable) if stdlib_path is None: - for lib_path in sys.path: - stdlib_path = sys.pypy_find_stdlib(lib_path) - if stdlib_path is not None: - break - if stdlib_path is None: initstdio() - print(STDLIB_WARNING, file=sys.stderr) + print(STDLIB_WARNING % (getattr(sys, 'prefix', '<missing>'), + file=sys.stderr) else: sys.path[:] = stdlib_path # from this point on, we are free to use all the unicode stuff we want, 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 @@ -641,6 +641,9 @@ assert round(5e15) == 5e15 assert round(-(5e15-1)) == -(5e15-1) assert round(-5e15) == -5e15 + assert round(5e15/2) == 5e15/2 + assert round((5e15+1)/2) == 5e15/2+1 + assert round((5e15-1)/2) == 5e15/2 # inf = 1e200 * 1e200 raises(OverflowError, round, inf) @@ -651,6 +654,12 @@ # assert round(562949953421312.5, 1) == 562949953421312.5 assert round(56294995342131.5, 3) == 56294995342131.5 + # + for i in range(-10, 10): + expected = i if i < 0 else i + 1 + assert round(i + 0.5) == round(i + 0.5, 0) == expected + x = i * 10 + 5 + assert round(x, -1) == round(float(x), -1) == expected * 10 assert round(0.0) == 0.0 assert type(round(0.0)) == int 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 @@ -3,7 +3,7 @@ from rpython.rlib import rdynload, clibffi from rpython.rtyper.lltypesystem import rffi -VERSION = "1.10.0" +VERSION = "1.11.0" FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI try: diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -91,6 +91,11 @@ w_result = self.ctype.float(ptr) return w_result + def complex(self): + with self as ptr: + w_result = self.ctype.complex(ptr) + return w_result + def len(self): from pypy.module._cffi_backend import ctypearray space = self.space @@ -405,6 +410,13 @@ with self as ptr: misc.write_raw_float_data(ptr, source, self.ctype.size) + def write_raw_complex_data(self, real, imag): + with self as ptr: + halfsize = self.ctype.size >> 1 + ptr2 = rffi.ptradd(ptr, halfsize) + misc.write_raw_float_data(ptr, real, halfsize) + misc.write_raw_float_data(ptr2, imag, halfsize) + def convert_to_object(self): with self as ptr: w_obj = self.ctype.convert_to_object(ptr) @@ -646,6 +658,7 @@ __int__ = interp2app(W_CData.int), __long__ = interp2app(W_CData.long), __float__ = interp2app(W_CData.float), + __complex__ = interp2app(W_CData.complex), __len__ = interp2app(W_CData.len), __lt__ = interp2app(W_CData.lt), __le__ = interp2app(W_CData.le), diff --git a/pypy/module/_cffi_backend/cffi_opcode.py b/pypy/module/_cffi_backend/cffi_opcode.py --- a/pypy/module/_cffi_backend/cffi_opcode.py +++ b/pypy/module/_cffi_backend/cffi_opcode.py @@ -105,8 +105,10 @@ PRIM_UINT_FAST64 = 45 PRIM_INTMAX = 46 PRIM_UINTMAX = 47 +PRIM_FLOATCOMPLEX = 48 +PRIM_DOUBLECOMPLEX = 49 -_NUM_PRIM = 48 +_NUM_PRIM = 50 _UNKNOWN_PRIM = -1 _UNKNOWN_FLOAT_PRIM = -2 _UNKNOWN_LONG_DOUBLE = -3 diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py --- a/pypy/module/_cffi_backend/ctypefunc.py +++ b/pypy/module/_cffi_backend/ctypefunc.py @@ -20,7 +20,7 @@ from pypy.module._cffi_backend.ctypestruct import W_CTypeStruct, W_CTypeUnion from pypy.module._cffi_backend.ctypeprim import (W_CTypePrimitiveSigned, W_CTypePrimitiveUnsigned, W_CTypePrimitiveCharOrUniChar, - W_CTypePrimitiveFloat, W_CTypePrimitiveLongDouble) + W_CTypePrimitiveFloat, W_CTypePrimitiveLongDouble, W_CTypePrimitiveComplex) class W_CTypeFunc(W_CTypePtrBase): @@ -212,18 +212,21 @@ # ---------- # We attach to the classes small methods that return a 'ffi_type' -def _missing_ffi_type(self, cifbuilder, is_result_type): - space = self.space - if self.size < 0: - raise oefmt(space.w_TypeError, - "ctype '%s' has incomplete type", self.name) + +def _notimplemented_ffi_type(self, is_result_type, extra=''): if is_result_type: place = "return value" else: place = "argument" - raise oefmt(space.w_NotImplementedError, - "ctype '%s' (size %d) not supported as %s", - self.name, self.size, place) + raise oefmt(self.space.w_NotImplementedError, + "ctype '%s' (size %d) not supported as %s%s", + self.name, self.size, place, extra) + +def _missing_ffi_type(self, cifbuilder, is_result_type): + if self.size < 0: + raise oefmt(self.space.w_TypeError, + "ctype '%s' has incomplete type", self.name) + raise _notimplemented_ffi_type(self, is_result_type) def _struct_ffi_type(self, cifbuilder, is_result_type): if self.size >= 0: @@ -260,6 +263,13 @@ def _primlongdouble_ffi_type(self, cifbuilder, is_result_type): return clibffi.ffi_type_longdouble +def _primcomplex_ffi_type(self, cifbuilder, is_result_type): + raise _notimplemented_ffi_type(self, is_result_type, + extra = " (the support for complex types inside libffi " + "is mostly missing at this point, so CFFI only " + "supports complex types as arguments or return " + "value in API-mode functions)") + def _ptr_ffi_type(self, cifbuilder, is_result_type): return clibffi.ffi_type_pointer @@ -276,6 +286,7 @@ W_CTypePrimitiveUnsigned._get_ffi_type = _primunsigned_ffi_type W_CTypePrimitiveFloat._get_ffi_type = _primfloat_ffi_type W_CTypePrimitiveLongDouble._get_ffi_type = _primlongdouble_ffi_type +W_CTypePrimitiveComplex._get_ffi_type = _primcomplex_ffi_type W_CTypePtrBase._get_ffi_type = _ptr_ffi_type W_CTypeVoid._get_ffi_type = _void_ffi_type # ---------- diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py --- a/pypy/module/_cffi_backend/ctypeobj.py +++ b/pypy/module/_cffi_backend/ctypeobj.py @@ -73,6 +73,14 @@ raise oefmt(space.w_TypeError, "float() not supported on cdata '%s'", self.name) + def complex(self, cdata): + # <cdata 'float'> or <cdata 'int'> cannot be directly converted by + # calling complex(), just like <cdata 'int'> cannot be directly + # converted by calling float() + space = self.space + raise oefmt(space.w_TypeError, "complex() not supported on cdata '%s'", + self.name) + def convert_to_object(self, cdata): space = self.space raise oefmt(space.w_TypeError, "cannot return a cdata '%s'", self.name) diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -532,3 +532,51 @@ @jit.dont_look_inside def nonzero(self, cdata): return misc.is_nonnull_longdouble(cdata) + + +class W_CTypePrimitiveComplex(W_CTypePrimitive): + _attrs_ = [] + + def cast(self, w_ob): + space = self.space + if isinstance(w_ob, cdataobj.W_CData): + if not isinstance(w_ob.ctype, W_CTypePrimitive): + raise oefmt(space.w_TypeError, + "cannot cast ctype '%s' to ctype '%s'", + w_ob.ctype.name, self.name) + w_ob = w_ob.convert_to_object() + # + imag = 0.0 + if space.isinstance_w(w_ob, space.w_bytes): + real = self.cast_str(w_ob) + elif space.isinstance_w(w_ob, space.w_unicode): + real = self.cast_unicode(w_ob) + else: + real, imag = space.unpackcomplex(w_ob) + w_cdata = cdataobj.W_CDataMem(space, self) + w_cdata.write_raw_complex_data(real, imag) + return w_cdata + + def complex(self, cdata): + return self.convert_to_object(cdata) + + def convert_to_object(self, cdata): + halfsize = self.size >> 1 + cdata2 = rffi.ptradd(cdata, halfsize) + real = misc.read_raw_float_data(cdata, halfsize) + imag = misc.read_raw_float_data(cdata2, halfsize) + return self.space.newcomplex(real, imag) + + def convert_from_object(self, cdata, w_ob): + space = self.space + real, imag = space.unpackcomplex(w_ob) + halfsize = self.size >> 1 + cdata2 = rffi.ptradd(cdata, halfsize) + misc.write_raw_float_data(cdata, real, halfsize) + misc.write_raw_float_data(cdata2, imag, halfsize) + + def nonzero(self, cdata): + halfsize = self.size >> 1 + cdata2 = rffi.ptradd(cdata, halfsize) + return (misc.is_nonnull_float(cdata, halfsize) | + misc.is_nonnull_float(cdata2, halfsize)) diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py --- a/pypy/module/_cffi_backend/newtype.py +++ b/pypy/module/_cffi_backend/newtype.py @@ -66,8 +66,8 @@ PRIMITIVE_TYPES = {} -def eptype(name, TYPE, ctypecls): - PRIMITIVE_TYPES[name] = ctypecls, rffi.sizeof(TYPE), alignment(TYPE) +def eptype(name, TYPE, ctypecls, rep=1): + PRIMITIVE_TYPES[name] = ctypecls, rffi.sizeof(TYPE) * rep, alignment(TYPE) def eptypesize(name, size, ctypecls): for TYPE in [lltype.Signed, lltype.SignedLongLong, rffi.SIGNEDCHAR, @@ -94,6 +94,9 @@ eptype("long double", rffi.LONGDOUBLE, ctypeprim.W_CTypePrimitiveLongDouble) eptype("_Bool", lltype.Bool, ctypeprim.W_CTypePrimitiveBool) +eptype("float _Complex", rffi.FLOAT, ctypeprim.W_CTypePrimitiveComplex, rep=2) +eptype("double _Complex", rffi.DOUBLE, ctypeprim.W_CTypePrimitiveComplex, rep=2) + eptypesize("int8_t", 1, ctypeprim.W_CTypePrimitiveSigned) eptypesize("uint8_t", 1, ctypeprim.W_CTypePrimitiveUnsigned) eptypesize("int16_t", 2, ctypeprim.W_CTypePrimitiveSigned) diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py --- a/pypy/module/_cffi_backend/realize_c_type.py +++ b/pypy/module/_cffi_backend/realize_c_type.py @@ -8,6 +8,7 @@ from pypy.module import _cffi_backend from pypy.module._cffi_backend.ctypeobj import W_CType from pypy.module._cffi_backend import cffi_opcode, newtype, ctypestruct +from pypy.module._cffi_backend import ctypeprim from pypy.module._cffi_backend import parse_c_type @@ -70,6 +71,8 @@ "uint_fast64_t", "intmax_t", "uintmax_t", + "float _Complex", + "double _Complex", ] assert len(NAMES) == cffi_opcode._NUM_PRIM @@ -209,7 +212,7 @@ # which the struct args are replaced with ptr-to- struct, and # a struct return value is replaced with a hidden first arg of # type ptr-to-struct. This is how recompiler.py produces - # trampoline functions for PyPy. + # trampoline functions for PyPy. (Same with complex numbers.) if self.nostruct_ctype is None: fargs, fret, ellipsis, abi = self._unpack(ffi) # 'locs' will be a string of the same length as the final fargs, @@ -218,11 +221,13 @@ locs = ['\x00'] * len(fargs) for i in range(len(fargs)): farg = fargs[i] - if isinstance(farg, ctypestruct.W_CTypeStructOrUnion): + if (isinstance(farg, ctypestruct.W_CTypeStructOrUnion) or + isinstance(farg, ctypeprim.W_CTypePrimitiveComplex)): farg = newtype.new_pointer_type(ffi.space, farg) fargs[i] = farg locs[i] = 'A' - if isinstance(fret, ctypestruct.W_CTypeStructOrUnion): + if (isinstance(fret, ctypestruct.W_CTypeStructOrUnion) or + isinstance(fret, ctypeprim.W_CTypePrimitiveComplex)): fret = newtype.new_pointer_type(ffi.space, fret) fargs = [fret] + fargs locs = ['R'] + locs 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 @@ -37,7 +37,7 @@ /* keywords */ TOK__BOOL, TOK_CHAR, - //TOK__COMPLEX, + TOK__COMPLEX, TOK_CONST, TOK_DOUBLE, TOK_ENUM, @@ -171,6 +171,7 @@ if (tok->size == 5 && !memcmp(p, "_Bool", 5)) tok->kind = TOK__BOOL; if (tok->size == 7 && !memcmp(p,"__cdecl",7)) tok->kind = TOK_CDECL; if (tok->size == 9 && !memcmp(p,"__stdcall",9))tok->kind = TOK_STDCALL; + if (tok->size == 8 && !memcmp(p,"_Complex",8)) tok->kind = TOK__COMPLEX; break; case 'c': if (tok->size == 4 && !memcmp(p, "char", 4)) tok->kind = TOK_CHAR; @@ -613,6 +614,7 @@ { unsigned int t0; _cffi_opcode_t t1; + _cffi_opcode_t t1complex; int modifiers_length, modifiers_sign; qualifiers: @@ -668,6 +670,8 @@ break; } + t1complex = 0; + if (modifiers_length || modifiers_sign) { switch (tok->kind) { @@ -678,6 +682,7 @@ case TOK_STRUCT: case TOK_UNION: case TOK_ENUM: + case TOK__COMPLEX: return parse_error(tok, "invalid combination of types"); case TOK_DOUBLE: @@ -731,9 +736,11 @@ break; case TOK_FLOAT: t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_FLOAT); + t1complex = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_FLOATCOMPLEX); break; case TOK_DOUBLE: t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_DOUBLE); + t1complex = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_DOUBLECOMPLEX); break; case TOK_IDENTIFIER: { @@ -800,6 +807,13 @@ } next_token(tok); } + if (tok->kind == TOK__COMPLEX) + { + if (t1complex == 0) + return parse_error(tok, "_Complex type combination unsupported"); + t1 = t1complex; + next_token(tok); + } return parse_sequel(tok, write_ds(tok, t1)); } diff --git a/pypy/module/_cffi_backend/src/parse_c_type.h b/pypy/module/_cffi_backend/src/parse_c_type.h --- a/pypy/module/_cffi_backend/src/parse_c_type.h +++ b/pypy/module/_cffi_backend/src/parse_c_type.h @@ -78,8 +78,10 @@ #define _CFFI_PRIM_UINT_FAST64 45 #define _CFFI_PRIM_INTMAX 46 #define _CFFI_PRIM_UINTMAX 47 +#define _CFFI_PRIM_FLOATCOMPLEX 48 +#define _CFFI_PRIM_DOUBLECOMPLEX 49 -#define _CFFI__NUM_PRIM 48 +#define _CFFI__NUM_PRIM 50 #define _CFFI__UNKNOWN_PRIM (-1) #define _CFFI__UNKNOWN_FLOAT_PRIM (-2) #define _CFFI__UNKNOWN_LONG_DOUBLE (-3) 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.10.0", ("This test_c.py file is for testing a version" +assert __version__ == "1.11.0", ("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,): @@ -174,37 +174,56 @@ py.test.raises(TypeError, cast, p, None) def test_complex_types(): - py.test.skip("later") INF = 1E200 * 1E200 for name in ["float", "double"]: - p = new_primitive_type("_Complex " + name) - assert bool(cast(p, 0)) + p = new_primitive_type(name + " _Complex") + assert bool(cast(p, 0)) is False assert bool(cast(p, INF)) assert bool(cast(p, -INF)) - assert bool(cast(p, 0j)) + assert bool(cast(p, 0j)) is False assert bool(cast(p, INF*1j)) assert bool(cast(p, -INF*1j)) + # "can't convert complex to float", like CPython's "float(0j)" py.test.raises(TypeError, int, cast(p, -150)) py.test.raises(TypeError, long, cast(p, -150)) py.test.raises(TypeError, float, cast(p, -150)) assert complex(cast(p, 1.25)) == 1.25 assert complex(cast(p, 1.25j)) == 1.25j - assert float(cast(p, INF*1j)) == INF*1j - assert float(cast(p, -INF)) == -INF + assert complex(cast(p, complex(0,INF))) == complex(0,INF) + assert complex(cast(p, -INF)) == -INF if name == "float": assert complex(cast(p, 1.1j)) != 1.1j # rounding error assert complex(cast(p, 1E200+3j)) == INF+3j # limited range - assert complex(cast(p, 3+1E200j)) == 3+INF*1j # limited range + assert complex(cast(p, complex(3,1E200))) == complex(3,INF) # limited range - assert cast(p, -1.1j) != cast(p, -1.1j) + assert cast(p, -1.1j) == cast(p, -1.1j) assert repr(complex(cast(p, -0.0)).real) == '-0.0' - assert repr(complex(cast(p, -0j))) == '-0j' - assert complex(cast(p, '\x09')) == 9.0 - assert complex(cast(p, True)) == 1.0 + #assert repr(complex(cast(p, -0j))) == '-0j' # http://bugs.python.org/issue29602 + assert complex(cast(p, b'\x09')) == 9.0 + 0j + assert complex(cast(p, u+'\x09')) == 9.0 + 0j + assert complex(cast(p, True)) == 1.0 + 0j py.test.raises(TypeError, cast, p, None) # - py.test.raises(cast, new_primitive_type(name), 1+2j) - py.test.raises(cast, new_primitive_type("int"), 1+2j) + py.test.raises(TypeError, cast, new_primitive_type(name), 1+0j) + # + for basetype in ["char", "int", "uint64_t", "float", + "double", "long double"]: + baseobj = cast(new_primitive_type(basetype), 65) + py.test.raises(TypeError, complex, baseobj) + # + BArray = new_array_type(new_pointer_type(p), 10) + x = newp(BArray, None) + x[5] = 12.34 + 56.78j + assert type(x[5]) is complex + assert abs(x[5] - (12.34 + 56.78j)) < 1e-5 + assert (x[5] == 12.34 + 56.78j) == (name == "double") # rounding error + # + class Foo: + def __complex__(self): + return 2 + 3j + assert complex(Foo()) == 2 + 3j + assert complex(cast(p, Foo())) == 2 + 3j + py.test.raises(TypeError, cast, new_primitive_type("int"), 1+0j) def test_character_type(): p = new_primitive_type("char") @@ -1105,6 +1124,34 @@ BSShort = new_primitive_type("short") assert f(3, cast(BSChar, -3), cast(BUChar, 200), cast(BSShort, -5)) == 192 +def test_call_function_24(): + BFloat = new_primitive_type("float") + BFloatComplex = new_primitive_type("float _Complex") + BFunc3 = new_function_type((BFloat, BFloat), BFloatComplex, False) + if 0: # libffi returning nonsense silently, so logic disabled for now + f = cast(BFunc3, _testfunc(24)) + result = f(1.25, 5.1) + assert type(result) == complex + assert result.real == 1.25 # exact + assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact + else: + f = cast(BFunc3, _testfunc(9)) + py.test.raises(NotImplementedError, f, 12.3, 34.5) + +def test_call_function_25(): + BDouble = new_primitive_type("double") + BDoubleComplex = new_primitive_type("double _Complex") + BFunc3 = new_function_type((BDouble, BDouble), BDoubleComplex, False) + if 0: # libffi returning nonsense silently, so logic disabled for now + f = cast(BFunc3, _testfunc(25)) + result = f(1.25, 5.1) + assert type(result) == complex + assert result.real == 1.25 # exact + assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-10) # inexact + else: + f = cast(BFunc3, _testfunc(9)) + py.test.raises(NotImplementedError, f, 12.3, 34.5) + def test_cannot_call_with_a_autocompleted_struct(): BSChar = new_primitive_type("signed char") BDouble = new_primitive_type("double") @@ -3796,7 +3843,7 @@ def test_char_pointer_conversion(): import warnings - assert __version__.startswith(("1.8", "1.9", "1.10")), ( + assert __version__.startswith(("1.8", "1.9", "1.10", "1.11")), ( "consider turning the warning into an error") BCharP = new_pointer_type(new_primitive_type("char")) BIntP = new_pointer_type(new_primitive_type("int")) diff --git a/pypy/module/_cffi_backend/test/test_parse_c_type.py b/pypy/module/_cffi_backend/test/test_parse_c_type.py --- a/pypy/module/_cffi_backend/test/test_parse_c_type.py +++ b/pypy/module/_cffi_backend/test/test_parse_c_type.py @@ -148,6 +148,8 @@ ("long int", cffi_opcode.PRIM_LONG), ("unsigned short", cffi_opcode.PRIM_USHORT), ("long double", cffi_opcode.PRIM_LONGDOUBLE), + (" float _Complex", cffi_opcode.PRIM_FLOATCOMPLEX), + ("double _Complex ", cffi_opcode.PRIM_DOUBLECOMPLEX), ]: assert parse(simple_type) == ['->', Prim(expected)] @@ -273,6 +275,11 @@ parse_error("int[5](*)", "unexpected symbol", 6) parse_error("int a(*)", "identifier expected", 6) parse_error("int[123456789012345678901234567890]", "number too large", 4) + # + parse_error("_Complex", "identifier expected", 0) + parse_error("int _Complex", "_Complex type combination unsupported", 4) + parse_error("long double _Complex", "_Complex type combination unsupported", + 12) def test_number_too_large(): num_max = sys.maxsize 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 @@ -1819,6 +1819,68 @@ assert lib.f.__get__(42) is lib.f assert lib.f.__get__(42, int) is lib.f + def test_function_returns_float_complex(self): + import sys + if sys.platform == 'win32': + skip("MSVC may not support _Complex") + ffi, lib = self.prepare( + "float _Complex f1(float a, float b);", + "test_function_returns_float_complex", """ + #include <complex.h> + static float _Complex f1(float a, float b) { return a + I*2.0*b; } + """, min_version=(1, 11, 0)) + result = lib.f1(1.25, 5.1) + assert type(result) == complex + assert result.real == 1.25 # exact + assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact + + def test_function_returns_double_complex(self): + import sys + if sys.platform == 'win32': + skip("MSVC may not support _Complex") + ffi, lib = self.prepare( + "double _Complex f1(double a, double b);", + "test_function_returns_double_complex", """ + #include <complex.h> + static double _Complex f1(double a, double b) { return a + I*2.0*b; } + """, min_version=(1, 11, 0)) + result = lib.f1(1.25, 5.1) + assert type(result) == complex + assert result.real == 1.25 # exact + assert result.imag == 2*5.1 # exact + + def test_function_argument_float_complex(self): + import sys + if sys.platform == 'win32': + skip("MSVC may not support _Complex") + ffi, lib = self.prepare( + "float f1(float _Complex x);", + "test_function_argument_float_complex", """ + #include <complex.h> + static float f1(float _Complex x) { return cabsf(x); } + """, min_version=(1, 11, 0)) + x = complex(12.34, 56.78) + result = lib.f1(x) + assert abs(result - abs(x)) < 1e-5 + result2 = lib.f1(ffi.cast("float _Complex", x)) + assert result2 == result + + def test_function_argument_double_complex(self): + import sys + if sys.platform == 'win32': + skip("MSVC may not support _Complex") + ffi, lib = self.prepare( + "double f1(double _Complex);", + "test_function_argument_double_complex", """ + #include <complex.h> + static double f1(double _Complex x) { return cabs(x); } + """, min_version=(1, 11, 0)) + x = complex(12.34, 56.78) + result = lib.f1(x) + assert abs(result - abs(x)) < 1e-11 + result2 = lib.f1(ffi.cast("double _Complex", x)) + assert result2 == result + def test_typedef_array_dotdotdot(self): ffi, lib = self.prepare(""" typedef int foo_t[...], bar_t[...]; diff --git a/pypy/module/_cffi_backend/wrapper.py b/pypy/module/_cffi_backend/wrapper.py --- a/pypy/module/_cffi_backend/wrapper.py +++ b/pypy/module/_cffi_backend/wrapper.py @@ -8,6 +8,7 @@ from pypy.module._cffi_backend.cdataobj import W_CData from pypy.module._cffi_backend.cdataobj import W_CDataPtrToStructOrUnion from pypy.module._cffi_backend.ctypeptr import W_CTypePtrOrArray +from pypy.module._cffi_backend.ctypeptr import W_CTypePointer from pypy.module._cffi_backend.ctypefunc import W_CTypeFunc from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion from pypy.module._cffi_backend import allocator @@ -83,8 +84,9 @@ # ctype._call(self.fnptr, args_w) # returns w_None # - assert isinstance(w_result_cdata, W_CDataPtrToStructOrUnion) - return w_result_cdata.structobj + ctyperesptr = w_result_cdata.ctype + assert isinstance(ctyperesptr, W_CTypePointer) + return w_result_cdata._do_getitem(ctyperesptr, 0) else: args_w = args_w[:] prepare_args(space, rawfunctype, args_w, 0) @@ -109,13 +111,14 @@ @jit.unroll_safe def prepare_args(space, rawfunctype, args_w, start_index): # replaces struct/union arguments with ptr-to-struct/union arguments + # as well as complex numbers locs = rawfunctype.nostruct_locs fargs = rawfunctype.nostruct_ctype.fargs for i in range(start_index, len(locs)): if locs[i] != 'A': continue w_arg = args_w[i] - farg = fargs[i] # <ptr to struct/union> + farg = fargs[i] # <ptr to struct/union/complex> assert isinstance(farg, W_CTypePtrOrArray) if isinstance(w_arg, W_CData) and w_arg.ctype is farg.ctitem: # fast way: we are given a W_CData "struct", so just make diff --git a/pypy/module/_socket/interp_socket.py b/pypy/module/_socket/interp_socket.py --- a/pypy/module/_socket/interp_socket.py +++ b/pypy/module/_socket/interp_socket.py @@ -380,6 +380,8 @@ return space.newint(self.sock.getsockopt_int(level, optname)) except SocketError as e: raise converted_error(space, e) + if buflen < 0 or buflen > 1024: + raise explicit_socket_error(space, "getsockopt buflen out of range") return space.newbytes(self.sock.getsockopt(level, optname, buflen)) def gettimeout_w(self, space): @@ -759,6 +761,12 @@ w_exception = space.call_function(w_exception_class, space.newtext(message)) raise OperationError(w_exception_class, w_exception) +def explicit_socket_error(space, msg): + w_exception_class = space.fromcache(SocketAPI).w_error + w_exception = space.call_function(w_exception_class, space.newtext(msg)) + return OperationError(w_exception_class, w_exception) + + # ____________________________________________________________ socketmethodnames = """ diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py --- a/pypy/module/_socket/test/test_sock_app.py +++ b/pypy/module/_socket/test/test_sock_app.py @@ -527,6 +527,16 @@ s.setsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 1) assert s.getsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 0) == 1 + def test_getsockopt_bad_length(self): + import _socket + s = _socket.socket() + buf = s.getsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 1024) + assert buf == b'\x00' * 4 + raises(_socket.error, s.getsockopt, + _socket.IPPROTO_TCP, _socket.TCP_NODELAY, 1025) + raises(_socket.error, s.getsockopt, + _socket.IPPROTO_TCP, _socket.TCP_NODELAY, -1) + def test_socket_ioctl(self): import _socket, sys if sys.platform != 'win32': diff --git a/pypy/module/cpyext/test/test_tupleobject.py b/pypy/module/cpyext/test/test_tupleobject.py --- a/pypy/module/cpyext/test/test_tupleobject.py +++ b/pypy/module/cpyext/test/test_tupleobject.py @@ -161,3 +161,47 @@ assert list(a) == list(range(100, 400, 100)) assert list(a) == list(range(100, 400, 100)) assert list(a) == list(range(100, 400, 100)) + + def test_setitem(self): + module = self.import_extension('foo', [ + ("set_after_use", "METH_O", + """ + PyObject *t2, *tuple = PyTuple_New(1); + PyObject * one = PyLong_FromLong(1); + int res; + Py_INCREF(one); + res = PyTuple_SetItem(tuple, 0, one); + if (res != 0) + { + Py_DECREF(tuple); + return NULL; + } + Py_INCREF(args); + res = PyTuple_SetItem(tuple, 0, args); + if (res != 0) + { + Py_DECREF(tuple); + return NULL; + } + /* Do something that uses the tuple, but does not incref */ + t2 = PyTuple_GetSlice(tuple, 0, 1); + Py_DECREF(t2); + Py_INCREF(one); + res = PyTuple_SetItem(tuple, 0, one); + Py_DECREF(tuple); + if (res != 0) + { + Py_DECREF(one); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; + """), + ]) + import sys + s = 'abc' + if '__pypy__' in sys.builtin_module_names: + raises(SystemError, module.set_after_use, s) + else: + module.set_after_use(s) + diff --git a/pypy/module/cpyext/tupleobject.py b/pypy/module/cpyext/tupleobject.py --- a/pypy/module/cpyext/tupleobject.py +++ b/pypy/module/cpyext/tupleobject.py @@ -6,7 +6,7 @@ PyVarObjectFields, cpython_struct, bootstrap_function, slot_function) from pypy.module.cpyext.pyobject import ( PyObject, PyObjectP, make_ref, from_ref, decref, incref, - track_reference, make_typedescr, get_typedescr) + track_reference, make_typedescr, get_typedescr, pyobj_has_w_obj) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.tupleobject import W_TupleObject @@ -132,19 +132,20 @@ @cpython_api([PyObject, Py_ssize_t, PyObject], rffi.INT_real, error=-1) def PyTuple_SetItem(space, ref, index, py_obj): - # XXX this will not complain when changing tuples that have - # already been realized as a W_TupleObject, but won't update the - # W_TupleObject if not tuple_check_ref(space, ref): decref(space, py_obj) PyErr_BadInternalCall(space) - ref = rffi.cast(PyTupleObject, ref) - size = ref.c_ob_size + tupleobj = rffi.cast(PyTupleObject, ref) + size = tupleobj.c_ob_size if index < 0 or index >= size: decref(space, py_obj) raise oefmt(space.w_IndexError, "tuple assignment index out of range") - old_ref = ref.c_ob_item[index] - ref.c_ob_item[index] = py_obj # consumes a reference + old_ref = tupleobj.c_ob_item[index] + if pyobj_has_w_obj(ref): + # similar but not quite equal to ref.c_ob_refcnt != 1 on CPython + raise oefmt(space.w_SystemError, "PyTuple_SetItem called on tuple after" + " use of tuple") + tupleobj.c_ob_item[index] = py_obj # consumes a reference if old_ref: decref(space, old_ref) return 0 diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py --- a/pypy/module/sys/__init__.py +++ b/pypy/module/sys/__init__.py @@ -39,8 +39,8 @@ 'byteorder' : 'space.newtext(sys.byteorder)', 'maxunicode' : 'space.newint(vm.MAXUNICODE)', 'pypy_objspaceclass' : 'space.newtext(repr(space))', - #'prefix' : # added by pypy_initial_path() when it - #'exec_prefix' : # succeeds, pointing to trunk or /usr + 'prefix' : 'state.get(space).w_initial_prefix', + 'exec_prefix' : 'state.get(space).w_initial_prefix', 'path' : 'state.get(space).w_path', 'modules' : 'state.get(space).w_modules', 'argv' : 'state.get(space).w_argv', diff --git a/pypy/module/sys/state.py b/pypy/module/sys/state.py --- a/pypy/module/sys/state.py +++ b/pypy/module/sys/state.py @@ -19,8 +19,11 @@ def setinitialpath(self, space): from pypy.module.sys.initpath import compute_stdlib_path + # This initial value for sys.prefix is normally overwritten + # at runtime by initpath.py + srcdir = os.path.dirname(pypydir) + self.w_initial_prefix = space.newtext(srcdir) # Initialize the default path - srcdir = os.path.dirname(pypydir) path = compute_stdlib_path(self, srcdir) self.w_path = space.newlist([space.newfilename(p) for p in path]) diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py @@ -229,13 +229,27 @@ # this checks that we get a sensible error if we try "int foo(...);" ffi = FFI() e = py.test.raises(CDefError, ffi.cdef, "int foo(...);") - assert str(e.value) == \ - "foo: a function with only '(...)' as argument is not correct C" + assert str(e.value) == ( + "<cdef source string>:1: foo: a function with only '(...)' " + "as argument is not correct C") def test_parse_error(): ffi = FFI() e = py.test.raises(CDefError, ffi.cdef, " x y z ") - assert re.match(r'cannot parse "x y z"\n:\d+:', str(e.value)) + assert str(e.value).startswith( + 'cannot parse "x y z"\n<cdef source string>:1:') + e = py.test.raises(CDefError, ffi.cdef, "\n\n\n x y z ") + assert str(e.value).startswith( + 'cannot parse "x y z"\n<cdef source string>:4:') + +def test_error_custom_lineno(): + ffi = FFI() + e = py.test.raises(CDefError, ffi.cdef, """ +# 42 "foobar" + + a b c d + """) + assert str(e.value).startswith('parse error\nfoobar:43:') def test_cannot_declare_enum_later(): ffi = FFI() @@ -279,7 +293,8 @@ def test_unknown_argument_type(): ffi = FFI() e = py.test.raises(CDefError, ffi.cdef, "void f(foobarbazzz);") - assert str(e.value) == ("f arg 1: unknown type 'foobarbazzz' (if you meant" + assert str(e.value) == ("<cdef source string>:1: f arg 1:" + " unknown type 'foobarbazzz' (if you meant" " to use the old C syntax of giving untyped" " arguments, it is not supported)") @@ -437,3 +452,9 @@ ffi._parser._declarations['extern_python foobar'] != ffi._parser._declarations['function bok'] == ffi._parser._declarations['extern_python bzrrr']) + +def test_error_invalid_syntax_for_cdef(): + ffi = FFI() + e = py.test.raises(CDefError, ffi.cdef, 'void foo(void) {}') + assert str(e.value) == ('<cdef source string>:1: unexpected <FuncDef>: ' + 'this construct is valid C but not valid in cdef()') diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py @@ -240,15 +240,18 @@ tp = model.PrimitiveType(typename) C = tp.is_char_type() F = tp.is_float_type() + X = tp.is_complex_type() I = tp.is_integer_type() assert C == (typename in ('char', 'wchar_t')) assert F == (typename in ('float', 'double', 'long double')) - assert I + F + C == 1 # one and only one of them is true + assert X == (typename in ('float _Complex', 'double _Complex')) + assert I + F + C + X == 1 # one and only one of them is true def test_all_integer_and_float_types(): typenames = [] for typename in all_primitive_types: if (all_primitive_types[typename] == 'c' or + all_primitive_types[typename] == 'j' or # complex typename == '_Bool' or typename == 'long double'): pass else: diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_new_ffi_1.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_new_ffi_1.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_new_ffi_1.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_new_ffi_1.py @@ -1705,6 +1705,8 @@ "ptrdiff_t", "size_t", "ssize_t", + 'float _Complex', + 'double _Complex', ]) for name in PRIMITIVE_TO_INDEX: x = ffi.sizeof(name) diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_parse_c_type.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_parse_c_type.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_parse_c_type.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_parse_c_type.py @@ -156,6 +156,8 @@ ("long int", lib._CFFI_PRIM_LONG), ("unsigned short", lib._CFFI_PRIM_USHORT), ("long double", lib._CFFI_PRIM_LONGDOUBLE), + (" float _Complex", lib._CFFI_PRIM_FLOATCOMPLEX), + ("double _Complex ", lib._CFFI_PRIM_DOUBLECOMPLEX), ]: assert parse(simple_type) == ['->', Prim(expected)] @@ -281,6 +283,11 @@ parse_error("int[5](*)", "unexpected symbol", 6) parse_error("int a(*)", "identifier expected", 6) parse_error("int[123456789012345678901234567890]", "number too large", 4) + # + parse_error("_Complex", "identifier expected", 0) + parse_error("int _Complex", "_Complex type combination unsupported", 4) + parse_error("long double _Complex", "_Complex type combination unsupported", + 12) def test_number_too_large(): num_max = sys.maxsize diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_realize_c_type.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_realize_c_type.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_realize_c_type.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_realize_c_type.py @@ -48,7 +48,6 @@ for name in cffi_opcode.PRIMITIVE_TO_INDEX: check(name, name) - def check_func(input, expected_output=None): import _cffi_backend ffi = _cffi_backend.FFI() diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py @@ -1553,7 +1553,8 @@ res = lib.bar(4, 5) assert res == 0 assert f.getvalue() == ( - b"extern \"Python\": function bar() called, but no code was attached " + b"extern \"Python\": function _CFFI_test_extern_python_1.bar() called, " + b"but no code was attached " b"to it yet with @ffi.def_extern(). Returning 0.\n") @ffi.def_extern("bar") @@ -2001,6 +2002,60 @@ """) assert lib.f1(52).a == 52 +def test_function_returns_float_complex(): + if sys.platform == 'win32': + py.test.skip("MSVC may not support _Complex") + ffi = FFI() + ffi.cdef("float _Complex f1(float a, float b);"); + lib = verify(ffi, "test_function_returns_float_complex", """ + #include <complex.h> + static float _Complex f1(float a, float b) { return a + I*2.0*b; } + """) + result = lib.f1(1.25, 5.1) + assert type(result) == complex + assert result.real == 1.25 # exact + assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact + +def test_function_returns_double_complex(): + if sys.platform == 'win32': + py.test.skip("MSVC may not support _Complex") + ffi = FFI() + ffi.cdef("double _Complex f1(double a, double b);"); + lib = verify(ffi, "test_function_returns_double_complex", """ + #include <complex.h> + static double _Complex f1(double a, double b) { return a + I*2.0*b; } + """) + result = lib.f1(1.25, 5.1) + assert type(result) == complex + assert result.real == 1.25 # exact + assert result.imag == 2*5.1 # exact + +def test_function_argument_float_complex(): + if sys.platform == 'win32': + py.test.skip("MSVC may not support _Complex") + ffi = FFI() + ffi.cdef("float f1(float _Complex x);"); + lib = verify(ffi, "test_function_argument_float_complex", """ + #include <complex.h> + static float f1(float _Complex x) { return cabsf(x); } + """) + x = complex(12.34, 56.78) + result = lib.f1(x) + assert abs(result - abs(x)) < 1e-5 + +def test_function_argument_double_complex(): + if sys.platform == 'win32': + py.test.skip("MSVC may not support _Complex") + ffi = FFI() + ffi.cdef("double f1(double _Complex);"); + lib = verify(ffi, "test_function_argument_double_complex", """ + #include <complex.h> + static double f1(double _Complex x) { return cabs(x); } + """) + x = complex(12.34, 56.78) + result = lib.f1(x) + assert abs(result - abs(x)) < 1e-11 + def test_typedef_array_dotdotdot(): ffi = FFI() ffi.cdef(""" diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py @@ -220,15 +220,18 @@ tp = model.PrimitiveType(typename) C = tp.is_char_type() F = tp.is_float_type() + X = tp.is_complex_type() I = tp.is_integer_type() assert C == (typename in ('char', 'wchar_t')) assert F == (typename in ('float', 'double', 'long double')) - assert I + F + C == 1 # one and only one of them is true + assert X == (typename in ('float _Complex', 'double _Complex')) + assert I + F + C + X == 1 # one and only one of them is true def test_all_integer_and_float_types(): typenames = [] for typename in all_primitive_types: if (all_primitive_types[typename] == 'c' or + all_primitive_types[typename] == 'j' or # complex typename == '_Bool' or typename == 'long double'): pass else: diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py --- a/pypy/objspace/std/bytesobject.py +++ b/pypy/objspace/std/bytesobject.py @@ -577,6 +577,7 @@ def descr_hash(self, space): x = compute_hash(self._value) + x -= (x == -1) # convert -1 to -2 without creating a bridge return space.newint(x) def descr_eq(self, space, w_other): diff --git a/pypy/objspace/std/test/test_bytesobject.py b/pypy/objspace/std/test/test_bytesobject.py --- a/pypy/objspace/std/test/test_bytesobject.py +++ b/pypy/objspace/std/test/test_bytesobject.py @@ -149,7 +149,6 @@ assert result == "a foo b" assert isinstance(result, cls) - for format, arg, cls in [("a %s b", "foo", str), (u"a %s b", u"foo", unicode)]: raises(TypeError, arg.__rmod__, format[:2]) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -323,6 +323,7 @@ def descr_hash(self, space): x = compute_hash(self._value) + x -= (x == -1) # convert -1 to -2 without creating a bridge return space.newint(x) def descr_eq(self, space, w_other): diff --git a/rpython/jit/backend/llsupport/test/test_gc_integration.py b/rpython/jit/backend/llsupport/test/test_gc_integration.py --- a/rpython/jit/backend/llsupport/test/test_gc_integration.py +++ b/rpython/jit/backend/llsupport/test/test_gc_integration.py @@ -463,6 +463,21 @@ def get_root_stack_top_addr(self): return rffi.cast(lltype.Signed, self.stack_addr) + def getlength(self): + top = self.stack_addr[0] + base = rffi.cast(lltype.Signed, self.stack) + n = (top - base) // WORD + assert 0 <= n < 10 + return n + + def curtop(self): + n = self.getlength() + return self.stack[n - 1] + + def settop(self, newvalue): + n = self.getlength() + self.stack[n - 1] = newvalue + class WriteBarrierDescr(AbstractDescr): jit_wb_cards_set = 0 jit_wb_if_flag_singlebyte = 1 @@ -645,7 +660,7 @@ frames = [] def check(i): - assert cpu.gc_ll_descr.gcrootmap.stack[0] == i + assert cpu.gc_ll_descr.gcrootmap.curtop() == i frame = rffi.cast(JITFRAMEPTR, i) assert len(frame.jf_frame) == self.cpu.JITFRAME_FIXED_SIZE + 4 # we "collect" @@ -665,14 +680,14 @@ assert gcmap == [22, 23, 24] for item, s in zip(gcmap, new_items): new_frame.jf_frame[item] = rffi.cast(lltype.Signed, s) - assert cpu.gc_ll_descr.gcrootmap.stack[0] == rffi.cast(lltype.Signed, frame) - cpu.gc_ll_descr.gcrootmap.stack[0] = rffi.cast(lltype.Signed, new_frame) + assert cpu.gc_ll_descr.gcrootmap.curtop() == rffi.cast(lltype.Signed, frame) + cpu.gc_ll_descr.gcrootmap.settop(rffi.cast(lltype.Signed, new_frame)) print '"Collecting" moved the frame from %d to %d' % ( - i, cpu.gc_ll_descr.gcrootmap.stack[0]) + i, cpu.gc_ll_descr.gcrootmap.curtop()) frames.append(new_frame) def check2(i): - assert cpu.gc_ll_descr.gcrootmap.stack[0] == i + assert cpu.gc_ll_descr.gcrootmap.curtop() == i frame = rffi.cast(JITFRAMEPTR, i) assert frame == frames[1] assert frame != frames[0] diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1052,17 +1052,19 @@ def _call_header_shadowstack(self, gcrootmap): rst = self._load_shadowstack_top_in_ebx(self.mc, gcrootmap) - self.mc.MOV_mr((ebx.value, 0), ebp.value) # MOV [ebx], ebp - self.mc.ADD_ri(ebx.value, WORD) + # the '1' is to benefit from the shadowstack 'is_minor' optimization + self.mc.MOV_mi((ebx.value, 0), 1) # MOV [ebx], 1 + self.mc.MOV_mr((ebx.value, WORD), ebp.value) # MOV [ebx + WORD], ebp + self.mc.ADD_ri(ebx.value, WORD * 2) self.mc.MOV(heap(rst), ebx) # MOV [rootstacktop], ebx def _call_footer_shadowstack(self, gcrootmap): rst = gcrootmap.get_root_stack_top_addr() if rx86.fits_in_32bits(rst): - self.mc.SUB_ji8(rst, WORD) # SUB [rootstacktop], WORD + self.mc.SUB_ji8(rst, WORD * 2) # SUB [rootstacktop], WORD * 2 else: self.mc.MOV_ri(ebx.value, rst) # MOV ebx, rootstacktop - self.mc.SUB_mi8((ebx.value, 0), WORD) # SUB [ebx], WORD + self.mc.SUB_mi8((ebx.value, 0), WORD * 2) # SUB [ebx], WORD * 2 def redirect_call_assembler(self, oldlooptoken, newlooptoken): # some minimal sanity checking diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -925,6 +925,10 @@ def gct_gc_adr_of_root_stack_top(self, hop): self._gc_adr_of_gcdata_attr(hop, 'root_stack_top') + def gct_gc_modified_shadowstack(self, hop): + # for stacklet + hop.genop("direct_call", [self.root_walker.gc_modified_shadowstack_ptr]) + def gct_gc_detach_callback_pieces(self, hop): op = hop.spaceop assert len(op.args) == 0 diff --git a/rpython/memory/gctransform/shadowstack.py b/rpython/memory/gctransform/shadowstack.py --- a/rpython/memory/gctransform/shadowstack.py +++ b/rpython/memory/gctransform/shadowstack.py @@ -245,6 +245,13 @@ from rpython.rlib import _stacklet_shadowstack _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit