[pypy-commit] pypy py3.5: hg merge default
rlamy
pypy.commits at gmail.com
Wed May 31 17:32:18 EDT 2017
Author: Ronan Lamy <ronan.lamy at 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
More information about the pypy-commit
mailing list