[pypy-commit] pypy test-cpyext: hg merge default
rlamy
pypy.commits at gmail.com
Fri Sep 30 13:54:09 EDT 2016
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: test-cpyext
Changeset: r87477:9929cb825a56
Date: 2016-09-30 18:36 +0100
http://bitbucket.org/pypy/pypy/changeset/9929cb825a56/
Log: hg merge default
diff too long, truncating to 2000 out of 5640 lines
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -40,4 +40,4 @@
# http://lists.gnu.org/archive/html/help-make/2010-08/msg00106.html
cffi_imports: pypy-c
- PYTHONPATH=. ./pypy-c pypy/tool/build_cffi_imports.py
+ PYTHONPATH=. ./pypy-c pypy/tool/build_cffi_imports.py || /bin/true
diff --git a/lib-python/2.7/distutils/sysconfig_pypy.py b/lib-python/2.7/distutils/sysconfig_pypy.py
--- a/lib-python/2.7/distutils/sysconfig_pypy.py
+++ b/lib-python/2.7/distutils/sysconfig_pypy.py
@@ -13,6 +13,7 @@
import sys
import os
import shlex
+import imp
from distutils.errors import DistutilsPlatformError
@@ -62,8 +63,7 @@
"""Initialize the module as appropriate for POSIX systems."""
g = {}
g['EXE'] = ""
- g['SO'] = ".so"
- g['SOABI'] = g['SO'].rsplit('.')[0]
+ g['SO'] = [s[0] for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION][0]
g['LIBDIR'] = os.path.join(sys.prefix, 'lib')
g['CC'] = "gcc -pthread" # -pthread might not be valid on OS/X, check
@@ -75,8 +75,7 @@
"""Initialize the module as appropriate for NT"""
g = {}
g['EXE'] = ".exe"
- g['SO'] = ".pyd"
- g['SOABI'] = g['SO'].rsplit('.')[0]
+ g['SO'] = [s[0] for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION][0]
global _config_vars
_config_vars = g
diff --git a/lib-python/2.7/sysconfig.py b/lib-python/2.7/sysconfig.py
--- a/lib-python/2.7/sysconfig.py
+++ b/lib-python/2.7/sysconfig.py
@@ -529,7 +529,7 @@
for suffix, mode, type_ in imp.get_suffixes():
if type_ == imp.C_EXTENSION:
_CONFIG_VARS['SOABI'] = suffix.split('.')[1]
- break
+ break
if args:
vals = []
diff --git a/lib_pypy/_subprocess.py b/lib_pypy/_subprocess.py
--- a/lib_pypy/_subprocess.py
+++ b/lib_pypy/_subprocess.py
@@ -22,7 +22,10 @@
code, message = _ffi.getwinerror()
raise WindowsError(code, message)
-_INVALID_HANDLE_VALUE = _ffi.cast("HANDLE", -1)
+def _int2handle(val):
+ return _ffi.cast("HANDLE", val)
+
+_INVALID_HANDLE_VALUE = _int2handle(-1)
class _handle(object):
def __init__(self, c_handle):
@@ -70,9 +73,9 @@
target = _ffi.new("HANDLE[1]")
res = _kernel32.DuplicateHandle(
- _ffi.cast("HANDLE", source_process),
- _ffi.cast("HANDLE", source),
- _ffi.cast("HANDLE", target_process),
+ _int2handle(source_process),
+ _int2handle(source),
+ _int2handle(target_process),
target, access, inherit, options)
if not res:
@@ -119,12 +122,14 @@
if not res:
raise _WinError()
- return _handle(pi.hProcess), _handle(pi.hThread), pi.dwProcessId, pi.dwThreadId
+ return (_handle(pi.hProcess),
+ _handle(pi.hThread),
+ pi.dwProcessId,
+ pi.dwThreadId)
def WaitForSingleObject(handle, milliseconds):
# CPython: the first argument is expected to be an integer.
- res = _kernel32.WaitForSingleObject(_ffi.cast("HANDLE", handle),
- milliseconds)
+ res = _kernel32.WaitForSingleObject(_int2handle(handle), milliseconds)
if res < 0:
raise _WinError()
@@ -134,7 +139,7 @@
# CPython: the first argument is expected to be an integer.
code = _ffi.new("DWORD[1]")
- res = _kernel32.GetExitCodeProcess(_ffi.cast("HANDLE", handle), code)
+ res = _kernel32.GetExitCodeProcess(_int2handle(handle), code)
if not res:
raise _WinError()
@@ -144,7 +149,7 @@
def TerminateProcess(handle, exitcode):
# CPython: the first argument is expected to be an integer.
# The second argument is silently wrapped in a UINT.
- res = _kernel32.TerminateProcess(_ffi.cast("HANDLE", handle),
+ res = _kernel32.TerminateProcess(_int2handle(handle),
_ffi.cast("UINT", exitcode))
if not res:
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.8.2
+Version: 1.8.4
Summary: Foreign Function Interface for Python calling C code.
Home-page: http://cffi.readthedocs.org
Author: Armin Rigo, Maciej Fijalkowski
diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py
--- a/lib_pypy/cffi/__init__.py
+++ b/lib_pypy/cffi/__init__.py
@@ -4,8 +4,8 @@
from .api import FFI, CDefError, FFIError
from .ffiplatform import VerificationError, VerificationMissing
-__version__ = "1.8.2"
-__version_info__ = (1, 8, 2)
+__version__ = "1.8.4"
+__version_info__ = (1, 8, 4)
# 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/_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.8.2"
+ "\ncompiled with cffi version: 1.8.4"
"\n_cffi_backend module: ", f);
modules = PyImport_GetModuleDict();
mod = PyDict_GetItemString(modules, "_cffi_backend");
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
@@ -332,7 +332,7 @@
realtype = model.unknown_ptr_type(decl.name)
else:
realtype, quals = self._get_type_and_quals(
- decl.type, name=decl.name)
+ decl.type, name=decl.name, partial_length_ok=True)
self._declare('typedef ' + decl.name, realtype, quals=quals)
else:
raise api.CDefError("unrecognized construct", decl)
@@ -781,11 +781,14 @@
exprnode.name in self._int_constants):
return self._int_constants[exprnode.name]
#
- if partial_length_ok:
- if (isinstance(exprnode, pycparser.c_ast.ID) and
+ if (isinstance(exprnode, pycparser.c_ast.ID) and
exprnode.name == '__dotdotdotarray__'):
+ if partial_length_ok:
self._partial_length = True
return '...'
+ raise api.FFIError(":%d: unsupported '[...]' here, cannot derive "
+ "the actual array length in this context"
+ % exprnode.coord.line)
#
raise api.FFIError(":%d: unsupported expression: expected a "
"simple numeric constant" % exprnode.coord.line)
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
@@ -587,8 +587,11 @@
# ----------
# typedefs
+ def _typedef_type(self, tp, name):
+ return self._global_type(tp, "(*(%s *)0)" % (name,))
+
def _generate_cpy_typedef_collecttype(self, tp, name):
- self._do_collect_type(tp)
+ self._do_collect_type(self._typedef_type(tp, name))
def _generate_cpy_typedef_decl(self, tp, name):
pass
@@ -598,6 +601,7 @@
self._lsts["typename"].append(TypenameExpr(name, type_index))
def _generate_cpy_typedef_ctx(self, tp, name):
+ tp = self._typedef_type(tp, name)
self._typedef_ctx(tp, name)
if getattr(tp, "origin", None) == "unknown_type":
self._struct_ctx(tp, tp.name, approxname=None)
diff --git a/pypy/doc/config/translation.profopt.txt b/pypy/doc/config/translation.profopt.txt
--- a/pypy/doc/config/translation.profopt.txt
+++ b/pypy/doc/config/translation.profopt.txt
@@ -3,3 +3,14 @@
RPython program) to gather profile data. Example for pypy-c: "-c 'from
richards import main;main(); from test import pystone;
pystone.main()'"
+
+NOTE: be aware of what this does in JIT-enabled executables. What it
+does is instrument and later optimize the C code that happens to run in
+the example you specify, ignoring any execution of the JIT-generated
+assembler. That means that you have to choose the example wisely. If
+it is something that will just generate assembler and stay there, there
+is little value. If it is something that exercises heavily library
+routines that are anyway written in C, then it will optimize that. Most
+interesting would be something that causes a lot of JIT-compilation,
+like running a medium-sized test suite several times in a row, in order
+to optimize the warm-up in general.
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
@@ -449,6 +449,27 @@
support (see ``multiline_input()``). On the other hand,
``parse_and_bind()`` calls are ignored (issue `#2072`_).
+* ``sys.getsizeof()`` always raises ``TypeError``. This is because a
+ memory profiler using this function is most likely to give results
+ inconsistent with reality on PyPy. It would be possible to have
+ ``sys.getsizeof()`` return a number (with enough work), but that may
+ or may not represent how much memory the object uses. It doesn't even
+ make really sense to ask how much *one* object uses, in isolation with
+ the rest of the system. For example, instances have maps, which are
+ often shared across many instances; in this case the maps would
+ probably be ignored by an implementation of ``sys.getsizeof()``, but
+ their overhead is important in some cases if they are many instances
+ with unique maps. Conversely, equal strings may share their internal
+ string data even if they are different objects---or empty containers
+ may share parts of their internals as long as they are empty. Even
+ stranger, some lists create objects as you read them; if you try to
+ estimate the size in memory of ``range(10**6)`` as the sum of all
+ items' size, that operation will by itself create one million integer
+ objects that never existed in the first place. Note that some of
+ these concerns also exist on CPython, just less so. For this reason
+ we explicitly don't implement ``sys.getsizeof()``.
+
+
.. _`is ignored in PyPy`: http://bugs.python.org/issue14621
.. _`little point`: http://events.ccc.de/congress/2012/Fahrplan/events/5152.en.html
.. _`#2072`: https://bitbucket.org/pypy/pypy/issue/2072/
diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst
--- a/pypy/doc/embedding.rst
+++ b/pypy/doc/embedding.rst
@@ -34,9 +34,11 @@
This function searches the PyPy standard library starting from the given
"PyPy home directory". The arguments are:
- * ``home``: NULL terminated path to an executable inside the pypy directory
+ * ``home``: path to an executable inside the pypy directory
(can be a .so name, can be made up). Used to look up the standard
- library, and is also set as ``sys.executable``.
+ library, and is also set as ``sys.executable``. From PyPy 5.5, you can
+ just say NULL here, as long as the ``libpypy-c.so/dylib/dll`` is itself
+ inside this directory.
* ``verbose``: if non-zero, it will print error messages to stderr
@@ -82,18 +84,14 @@
Note that this API is a lot more minimal than say CPython C API, so at first
it's obvious to think that you can't do much. However, the trick is to do
-all the logic in Python and expose it via `cffi`_ callbacks. Let's assume
-we're on linux and pypy is installed in ``/opt/pypy`` (with
-subdirectories like ``lib-python`` and ``lib_pypy``), and with the
-library in ``/opt/pypy/bin/libpypy-c.so``. (It doesn't need to be
-installed; you can also replace these paths with a local extract of the
-installation tarballs, or with your local checkout of pypy.) We write a
-little C program:
+all the logic in Python and expose it via `cffi`_ callbacks.
+We write a little C program:
.. code-block:: c
#include "PyPy.h"
#include <stdio.h>
+ #include <stdlib.h>
static char source[] = "print 'hello from pypy'";
@@ -102,9 +100,9 @@
int res;
rpython_startup_code();
- /* note: in the path /opt/pypy/x, the final x is ignored and
- replaced with lib-python and lib_pypy. */
- res = pypy_setup_home("/opt/pypy/x", 1);
+ /* Before PyPy 5.5, you may need to say e.g. "/opt/pypy/bin" instead
+ * of NULL. */
+ res = pypy_setup_home(NULL, 1);
if (res) {
printf("Error setting pypy home!\n");
return 1;
@@ -123,11 +121,6 @@
$ LD_LIBRARY_PATH=/opt/pypy/bin ./x
hello from pypy
-.. note:: If the compilation fails because of missing PyPy.h header file,
- you are running PyPy <= 2.2.1. Get it here__.
-
-.. __: https://bitbucket.org/pypy/pypy/raw/c4cd6eca9358066571500ac82aaacfdaa3889e8c/include/PyPy.h
-
On OSX it is necessary to set the rpath of the binary if one wants to link to it,
with a command like::
@@ -181,6 +174,7 @@
/* C example */
#include "PyPy.h"
#include <stdio.h>
+ #include <stdlib.h>
struct API {
double (*add_numbers)(double x, double y);
@@ -196,7 +190,7 @@
int res;
rpython_startup_code();
- res = pypy_setup_home("/opt/pypy/x", 1);
+ res = pypy_setup_home(NULL, 1);
if (res) {
fprintf(stderr, "Error setting pypy home!\n");
return -1;
@@ -237,6 +231,8 @@
Finding pypy_home
-----------------
+**You can usually skip this section if you are running PyPy >= 5.5.**
+
The function pypy_setup_home() takes as first parameter the path to a
file from which it can deduce the location of the standard library.
More precisely, it tries to remove final components until it finds
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
@@ -16,3 +16,29 @@
Improve merging of virtual states in the JIT in order to avoid jumping to the
preamble. Accomplished by allocating virtual objects where non-virtuals are
expected.
+
+.. branch: conditional_call_value_3
+JIT residual calls: if the called function starts with a fast-path
+like "if x.foo != 0: return x.foo", then inline the check before
+doing the CALL. For now, string hashing is about the only case.
+
+.. branch: search-path-from-libpypy
+
+The compiled pypy now looks for its lib-python/lib_pypy path starting
+from the location of the *libpypy-c* instead of the executable. This is
+arguably more consistent, and also it is what occurs anyway if you're
+embedding pypy. Linux distribution packagers, take note! At a minimum,
+the ``libpypy-c.so`` must really be inside the path containing
+``lib-python`` and ``lib_pypy``. Of course, you can put a symlink to it
+from somewhere else. You no longer have to do the same with the
+``pypy`` executable, as long as it finds its ``libpypy-c.so`` library.
+
+.. branch: _warning
+
+CPython allows warning.warn(('something', 1), Warning), on PyPy this
+produced a "expected a readable buffer object" error. Test and fix.
+
+.. branch: stricter-strip
+
+CPython rejects 'a'.strip(buffer(' ')); only None, str or unicode are
+allowed as arguments. Test and fix for str and unicode
diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -89,17 +89,18 @@
def pypy_setup_home(ll_home, verbose):
from pypy.module.sys.initpath import pypy_find_stdlib
verbose = rffi.cast(lltype.Signed, verbose)
- if ll_home:
+ if ll_home and ord(ll_home[0]):
home1 = rffi.charp2str(ll_home)
home = os.path.join(home1, 'x') # <- so that 'll_home' can be
# directly the root directory
else:
- home = home1 = pypydir
+ home1 = "pypy's shared library location"
+ home = '*'
w_path = pypy_find_stdlib(space, home)
if space.is_none(w_path):
if verbose:
debug("pypy_setup_home: directories 'lib-python' and 'lib_pypy'"
- " not found in '%s' or in any parent directory" % home1)
+ " not found in %s or in any parent directory" % home1)
return rffi.cast(rffi.INT, 1)
space.startup()
space.appexec([w_path], """(path):
@@ -239,6 +240,10 @@
raise Exception("Cannot use the --output option with PyPy "
"when --shared is on (it is by default). "
"See issue #1971.")
+ if config.translation.profopt is not None:
+ raise Exception("Cannot use the --profopt option "
+ "when --shared is on (it is by default). "
+ "See issue #2398.")
if sys.platform == 'win32':
libdir = thisdir.join('..', '..', 'libs')
libdir.ensure(dir=1)
@@ -298,37 +303,20 @@
# HACKHACKHACK
# ugly hack to modify target goal from compile_* to build_cffi_imports
# this should probably get cleaned up and merged with driver.create_exe
+ from rpython.tool.runsubprocess import run_subprocess
from rpython.translator.driver import taskdef
import types
- class Options(object):
- pass
-
-
- def mkexename(name):
- if sys.platform == 'win32':
- name = name.new(ext='exe')
- return name
-
compile_goal, = driver.backend_select_goals(['compile'])
@taskdef([compile_goal], "Create cffi bindings for modules")
def task_build_cffi_imports(self):
- from pypy.tool.build_cffi_imports import create_cffi_import_libraries
''' Use cffi to compile cffi interfaces to modules'''
- exename = mkexename(driver.compute_exe_name())
- basedir = exename
- while not basedir.join('include').exists():
- _basedir = basedir.dirpath()
- if _basedir == basedir:
- raise ValueError('interpreter %s not inside pypy repo',
- str(exename))
- basedir = _basedir
- modules = self.config.objspace.usemodules.getpaths()
- options = Options()
- # XXX possibly adapt options using modules
- failures = create_cffi_import_libraries(exename, options, basedir)
- # if failures, they were already printed
- print >> sys.stderr, str(exename),'successfully built (errors, if any, while building the above modules are ignored)'
+ filename = os.path.join(pypydir, 'tool', 'build_cffi_imports.py')
+ status, out, err = run_subprocess(str(driver.compute_exe_name()),
+ [filename])
+ sys.stdout.write(out)
+ sys.stderr.write(err)
+ # otherwise, ignore errors
driver.task_build_cffi_imports = types.MethodType(task_build_cffi_imports, driver)
driver.tasks['build_cffi_imports'] = driver.task_build_cffi_imports, [compile_goal]
driver.default_goal = 'build_cffi_imports'
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -375,12 +375,12 @@
class BufferInterfaceNotFound(Exception):
pass
+ at specialize.memo()
def wrappable_class_name(Class):
try:
return Class.typedef.name
except AttributeError:
return 'internal subclass of %s' % (Class.__name__,)
-wrappable_class_name._annspecialcase_ = 'specialize:memo'
class CannotHaveLock(Exception):
"""Raised by space.allocate_lock() if we're translating."""
@@ -829,12 +829,13 @@
assert type(s) is str
return self.interned_strings.get(s) is not None
+ @specialize.arg(1)
def descr_self_interp_w(self, RequiredClass, w_obj):
if not isinstance(w_obj, RequiredClass):
raise DescrMismatch()
return w_obj
- descr_self_interp_w._annspecialcase_ = 'specialize:arg(1)'
+ @specialize.arg(1)
def interp_w(self, RequiredClass, w_obj, can_be_None=False):
"""
Unwrap w_obj, checking that it is an instance of the required internal
@@ -849,7 +850,6 @@
wrappable_class_name(RequiredClass),
w_obj.getclass(self))
return w_obj
- interp_w._annspecialcase_ = 'specialize:arg(1)'
def unpackiterable(self, w_iterable, expected_length=-1):
"""Unpack an iterable into a real (interpreter-level) list.
@@ -1288,6 +1288,7 @@
self.setitem(w_globals, w_key, self.wrap(self.builtin))
return statement.exec_code(self, w_globals, w_locals)
+ @specialize.arg(2)
def appexec(self, posargs_w, source):
""" return value from executing given source at applevel.
EXPERIMENTAL. The source must look like
@@ -1299,7 +1300,6 @@
w_func = self.fromcache(AppExecCache).getorbuild(source)
args = Arguments(self, list(posargs_w))
return self.call_args(w_func, args)
- appexec._annspecialcase_ = 'specialize:arg(2)'
def _next_or_none(self, w_it):
try:
@@ -1309,6 +1309,7 @@
raise
return None
+ @specialize.arg(3)
def compare_by_iteration(self, w_iterable1, w_iterable2, op):
w_it1 = self.iter(w_iterable1)
w_it2 = self.iter(w_iterable2)
@@ -1331,7 +1332,6 @@
if op == 'gt': return self.gt(w_x1, w_x2)
if op == 'ge': return self.ge(w_x1, w_x2)
assert False, "bad value for op"
- compare_by_iteration._annspecialcase_ = 'specialize:arg(3)'
def decode_index(self, w_index_or_slice, seqlength):
"""Helper for custom sequence implementations
@@ -1974,6 +1974,7 @@
'ZeroDivisionError',
'RuntimeWarning',
'PendingDeprecationWarning',
+ 'UserWarning',
]
if sys.platform.startswith("win"):
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -374,11 +374,8 @@
self._value = value
self.setup(w_type)
- def get_w_value(self, space):
- w_value = self._w_value
- if w_value is None:
- self._w_value = w_value = space.wrap(self._value)
- return w_value
+ def _compute_value(self, space):
+ return self._value
@specialize.memo()
def get_operr_class(valuefmt):
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -2,7 +2,7 @@
from pypy.interpreter.error import OperationError, get_cleared_operation_error
from rpython.rlib.unroll import unrolling_iterable
from rpython.rlib.objectmodel import specialize
-from rpython.rlib import jit, rgc
+from rpython.rlib import jit, rgc, objectmodel
TICK_COUNTER_STEP = 100
@@ -131,6 +131,7 @@
if self.gettrace() is not None:
self._trace(frame, 'return', w_retval)
+ @objectmodel.always_inline
def bytecode_trace(self, frame, decr_by=TICK_COUNTER_STEP):
"Trace function called before each bytecode."
# this is split into a fast path and a slower path that is
@@ -139,7 +140,6 @@
actionflag = self.space.actionflag
if actionflag.decrement_ticker(decr_by) < 0:
actionflag.action_dispatcher(self, frame) # slow path
- bytecode_trace._always_inline_ = True
def _run_finalizers_now(self):
# Tests only: run the actions now, to ensure that the
@@ -147,6 +147,7 @@
# pypy.tool.pytest.apptest.
self.space.actionflag.action_dispatcher(self, None)
+ @objectmodel.always_inline
def bytecode_only_trace(self, frame):
"""
Like bytecode_trace() but doesn't invoke any other events besides the
@@ -156,7 +157,6 @@
self.gettrace() is None):
return
self.run_trace_func(frame)
- bytecode_only_trace._always_inline_ = True
@jit.unroll_safe
def run_trace_func(self, frame):
@@ -203,13 +203,13 @@
d.instr_prev_plus_one = frame.last_instr + 1
+ @objectmodel.try_inline
def bytecode_trace_after_exception(self, frame):
"Like bytecode_trace(), but without increasing the ticker."
actionflag = self.space.actionflag
self.bytecode_only_trace(frame)
if actionflag.get_ticker() < 0:
actionflag.action_dispatcher(self, frame) # slow path
- bytecode_trace_after_exception._always_inline_ = 'try'
# NB. this function is not inlined right now. backendopt.inline would
# need some improvements to handle this case, but it's not really an
# issue
@@ -456,6 +456,7 @@
periodic_actions = unrolling_iterable(self._periodic_actions)
@jit.unroll_safe
+ @objectmodel.dont_inline
def action_dispatcher(ec, frame):
# periodic actions (first reset the bytecode counter)
self.reset_ticker(self.checkinterval_scaled)
@@ -477,7 +478,6 @@
action._fired = False
action.perform(ec, frame)
- action_dispatcher._dont_inline_ = True
self.action_dispatcher = action_dispatcher
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -63,7 +63,7 @@
"""x.__iter__() <==> iter(x)"""
return self.space.wrap(self)
- def descr_send(self, w_arg=None):
+ def descr_send(self, w_arg):
"""send(arg) -> send 'arg' into generator,
return next yielded value or raise StopIteration."""
return self.send_ex(w_arg)
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -264,25 +264,22 @@
try:
executioncontext.call_trace(self)
#
- if operr is not None:
- ec = self.space.getexecutioncontext()
- next_instr = self.handle_operation_error(ec, operr)
- self.last_instr = intmask(next_instr - 1)
- else:
- # Execution starts just after the last_instr. Initially,
- # last_instr is -1. After a generator suspends it points to
- # the YIELD_VALUE instruction.
- next_instr = r_uint(self.last_instr + 1)
- if next_instr != 0:
- self.pushvalue(w_inputvalue)
- #
try:
+ if operr is not None:
+ ec = self.space.getexecutioncontext()
+ next_instr = self.handle_operation_error(ec, operr)
+ self.last_instr = intmask(next_instr - 1)
+ else:
+ # Execution starts just after the last_instr. Initially,
+ # last_instr is -1. After a generator suspends it points to
+ # the YIELD_VALUE instruction.
+ next_instr = r_uint(self.last_instr + 1)
+ if next_instr != 0:
+ self.pushvalue(w_inputvalue)
w_exitvalue = self.dispatch(self.pycode, next_instr,
executioncontext)
- except Exception:
- executioncontext.return_trace(self, self.space.w_None)
- raise
- executioncontext.return_trace(self, w_exitvalue)
+ finally:
+ executioncontext.return_trace(self, w_exitvalue)
# it used to say self.last_exception = None
# this is now done by the code in pypyjit module
# since we don't want to invalidate the virtualizable
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -6,7 +6,8 @@
from rpython.rlib import jit, rstackovf
from rpython.rlib.debug import check_nonneg
-from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.objectmodel import (we_are_translated, always_inline,
+ dont_inline)
from rpython.rlib.rarithmetic import r_uint, intmask
from rpython.tool.sourcetools import func_with_new_name
@@ -483,20 +484,20 @@
# of oparg failed to produce an integer which is annotated as non-neg
check_nonneg(oparg)
+ @always_inline
def LOAD_FAST(self, varindex, next_instr):
# access a local variable directly
w_value = self.locals_cells_stack_w[varindex]
if w_value is None:
self._load_fast_failed(varindex)
self.pushvalue(w_value)
- LOAD_FAST._always_inline_ = True
+ @dont_inline
def _load_fast_failed(self, varindex):
varname = self.getlocalvarname(varindex)
raise oefmt(self.space.w_UnboundLocalError,
"local variable '%s' referenced before assignment",
varname)
- _load_fast_failed._dont_inline_ = True
def LOAD_CONST(self, constindex, next_instr):
w_const = self.getconstant_w(constindex)
@@ -888,6 +889,7 @@
return
self.LOAD_GLOBAL(nameindex, next_instr) # fall-back
+ @always_inline
def _load_global(self, varname):
w_value = self.space.finditem_str(self.get_w_globals(), varname)
if w_value is None:
@@ -896,16 +898,15 @@
if w_value is None:
self._load_global_failed(varname)
return w_value
- _load_global._always_inline_ = True
+ @dont_inline
def _load_global_failed(self, varname):
raise oefmt(self.space.w_NameError,
"global name '%s' is not defined", varname)
- _load_global_failed._dont_inline_ = True
+ @always_inline
def LOAD_GLOBAL(self, nameindex, next_instr):
self.pushvalue(self._load_global(self.getname_u(nameindex)))
- LOAD_GLOBAL._always_inline_ = True
def DELETE_FAST(self, varindex, next_instr):
if self.locals_cells_stack_w[varindex] is None:
@@ -939,6 +940,7 @@
self.pushvalue(space.newlist([], sizehint=length_hint))
self.pushvalue(last_val)
+ @always_inline
def LOAD_ATTR(self, nameindex, next_instr):
"obj.attributename"
w_obj = self.popvalue()
@@ -949,7 +951,6 @@
w_attributename = self.getname_w(nameindex)
w_value = self.space.getattr(w_obj, w_attributename)
self.pushvalue(w_value)
- LOAD_ATTR._always_inline_ = True
@jit.unroll_safe
def cmp_exc_match(self, w_1, w_2):
diff --git a/pypy/interpreter/test/test_app_main.py b/pypy/interpreter/test/test_app_main.py
--- a/pypy/interpreter/test/test_app_main.py
+++ b/pypy/interpreter/test/test_app_main.py
@@ -1019,23 +1019,32 @@
old_sys_path = sys.path[:]
old_cwd = os.getcwd()
- sys.path.append(self.goal_dir)
# make sure cwd does not contain a stdlib
if self.tmp_dir.startswith(self.trunkdir):
skip('TMPDIR is inside the PyPy source')
- os.chdir(self.tmp_dir)
+ sys.path.append(self.goal_dir)
tmp_pypy_c = os.path.join(self.tmp_dir, 'pypy-c')
try:
+ os.chdir(self.tmp_dir)
+
+ # If we are running PyPy with a libpypy-c, the following
+ # lines find the stdlib anyway. Otherwise, it is not found.
+ expected_found = (
+ getattr(sys, 'pypy_translation_info', {})
+ .get('translation.shared'))
+
import app_main
- app_main.setup_bootstrap_path(tmp_pypy_c) # stdlib not found
+ app_main.setup_bootstrap_path(tmp_pypy_c)
assert sys.executable == ''
- assert sys.path == old_sys_path + [self.goal_dir]
+ if not expected_found:
+ assert sys.path == old_sys_path + [self.goal_dir]
app_main.setup_bootstrap_path(self.fake_exe)
if not sys.platform == 'win32':
# an existing file is always 'executable' on windows
assert sys.executable == '' # not executable!
- assert sys.path == old_sys_path + [self.goal_dir]
+ if not expected_found:
+ assert sys.path == old_sys_path + [self.goal_dir]
os.chmod(self.fake_exe, 0755)
app_main.setup_bootstrap_path(self.fake_exe)
@@ -1046,7 +1055,8 @@
if newpath[0].endswith('__extensions__'):
newpath = newpath[1:]
# we get at least 'expected_path', and maybe more (e.g.plat-linux2)
- assert newpath[:len(self.expected_path)] == self.expected_path
+ if not expected_found:
+ assert newpath[:len(self.expected_path)] == self.expected_path
finally:
sys.path[:] = old_sys_path
os.chdir(old_cwd)
diff --git a/pypy/interpreter/test/test_generator.py b/pypy/interpreter/test/test_generator.py
--- a/pypy/interpreter/test/test_generator.py
+++ b/pypy/interpreter/test/test_generator.py
@@ -57,12 +57,14 @@
def f():
yield 2
g = f()
+ # two arguments version
raises(NameError, g.throw, NameError, "Error")
def test_throw2(self):
def f():
yield 2
g = f()
+ # single argument version
raises(NameError, g.throw, NameError("Error"))
def test_throw3(self):
@@ -221,7 +223,8 @@
def f():
yield 1
g = f()
- raises(TypeError, g.send, 1)
+ raises(TypeError, g.send) # one argument required
+ raises(TypeError, g.send, 1) # not started, must send None
def test_generator_explicit_stopiteration(self):
def f():
diff --git a/pypy/interpreter/test/test_pyframe.py b/pypy/interpreter/test/test_pyframe.py
--- a/pypy/interpreter/test/test_pyframe.py
+++ b/pypy/interpreter/test/test_pyframe.py
@@ -562,3 +562,21 @@
res = f(10).g()
sys.settrace(None)
assert res == 10
+
+ def test_throw_trace_bug(self):
+ import sys
+ def f():
+ yield 5
+ gen = f()
+ assert next(gen) == 5
+ seen = []
+ def trace_func(frame, event, *args):
+ seen.append(event)
+ return trace_func
+ sys.settrace(trace_func)
+ try:
+ gen.throw(ValueError)
+ except ValueError:
+ pass
+ sys.settrace(None)
+ assert seen == ['call', 'exception', 'return']
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -109,6 +109,7 @@
# we need two subclasses of the app-level type, one to add mapdict, and then one
# to add del to not slow down the GC.
+ at specialize.memo()
def get_unique_interplevel_subclass(space, cls):
"NOT_RPYTHON: initialization-time only"
assert cls.typedef.acceptable_as_base_class
@@ -119,7 +120,6 @@
assert cls not in _unique_subclass_cache
_unique_subclass_cache[cls] = subcls
return subcls
-get_unique_interplevel_subclass._annspecialcase_ = "specialize:memo"
_unique_subclass_cache = {}
def _getusercls(cls, reallywantdict=False):
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, entrypoint
from rpython.rtyper.lltypesystem import rffi
-VERSION = "1.8.2"
+VERSION = "1.8.4"
FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI
try:
diff --git a/pypy/module/_cffi_backend/ctypearray.py b/pypy/module/_cffi_backend/ctypearray.py
--- a/pypy/module/_cffi_backend/ctypearray.py
+++ b/pypy/module/_cffi_backend/ctypearray.py
@@ -11,7 +11,7 @@
from rpython.rlib.rarithmetic import ovfcheck
from pypy.module._cffi_backend import cdataobj
-from pypy.module._cffi_backend.ctypeptr import W_CTypePtrOrArray
+from pypy.module._cffi_backend.ctypeptr import W_CTypePtrOrArray, W_CTypePointer
from pypy.module._cffi_backend import ctypeprim
@@ -22,6 +22,7 @@
is_nonfunc_pointer_or_array = True
def __init__(self, space, ctptr, length, arraysize, extra):
+ assert isinstance(ctptr, W_CTypePointer)
W_CTypePtrOrArray.__init__(self, space, arraysize, extra, 0,
ctptr.ctitem)
self.length = length
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
@@ -35,8 +35,7 @@
assert isinstance(ellipsis, bool)
extra, xpos = self._compute_extra_text(fargs, fresult, ellipsis, abi)
size = rffi.sizeof(rffi.VOIDP)
- W_CTypePtrBase.__init__(self, space, size, extra, xpos, fresult,
- could_cast_anything=False)
+ W_CTypePtrBase.__init__(self, space, size, extra, xpos, fresult)
self.fargs = fargs
self.ellipsis = ellipsis
self.abi = abi
@@ -59,6 +58,16 @@
lltype.free(self.cif_descr, flavor='raw')
self.cif_descr = lltype.nullptr(CIF_DESCRIPTION)
+ def is_unichar_ptr_or_array(self):
+ return False
+
+ def is_char_or_unichar_ptr_or_array(self):
+ return False
+
+ def string(self, cdataobj, maxlen):
+ # Can't use ffi.string() on a function pointer
+ return W_CType.string(self, cdataobj, maxlen)
+
def new_ctypefunc_completing_argtypes(self, args_w):
space = self.space
nargs_declared = len(self.fargs)
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
@@ -19,7 +19,6 @@
# XXX this could be improved with an elidable method get_size()
# that raises in case it's still -1...
- cast_anything = False
is_primitive_integer = False
is_nonfunc_pointer_or_array = False
is_indirect_arg_for_call_python = False
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
@@ -120,7 +120,6 @@
class W_CTypePrimitiveChar(W_CTypePrimitiveCharOrUniChar):
_attrs_ = []
- cast_anything = True
def cast_to_int(self, cdata):
return self.space.wrap(ord(cdata[0]))
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -14,12 +14,11 @@
class W_CTypePtrOrArray(W_CType):
- _attrs_ = ['ctitem', 'can_cast_anything', 'accept_str', 'length']
- _immutable_fields_ = ['ctitem', 'can_cast_anything', 'accept_str', 'length']
+ _attrs_ = ['ctitem', 'accept_str', 'length']
+ _immutable_fields_ = ['ctitem', 'accept_str', 'length']
length = -1
- def __init__(self, space, size, extra, extra_position, ctitem,
- could_cast_anything=True):
+ def __init__(self, space, size, extra, extra_position, ctitem):
name, name_position = ctitem.insert_name(extra, extra_position)
W_CType.__init__(self, space, size, name, name_position)
# this is the "underlying type":
@@ -27,10 +26,11 @@
# - for arrays, it is the array item type
# - for functions, it is the return type
self.ctitem = ctitem
- self.can_cast_anything = could_cast_anything and ctitem.cast_anything
- self.accept_str = (self.can_cast_anything or
- (ctitem.is_primitive_integer and
- ctitem.size == rffi.sizeof(lltype.Char)))
+ self.accept_str = (self.is_nonfunc_pointer_or_array and
+ (isinstance(ctitem, ctypevoid.W_CTypeVoid) or
+ isinstance(ctitem, ctypeprim.W_CTypePrimitiveChar) or
+ (ctitem.is_primitive_integer and
+ ctitem.size == rffi.sizeof(lltype.Char))))
def is_unichar_ptr_or_array(self):
return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveUniChar)
@@ -137,7 +137,10 @@
class W_CTypePtrBase(W_CTypePtrOrArray):
# base class for both pointers and pointers-to-functions
- _attrs_ = []
+ _attrs_ = ['is_void_ptr', 'is_voidchar_ptr']
+ _immutable_fields_ = ['is_void_ptr', 'is_voidchar_ptr']
+ is_void_ptr = False
+ is_voidchar_ptr = False
def convert_to_object(self, cdata):
ptrdata = rffi.cast(rffi.CCHARPP, cdata)[0]
@@ -154,7 +157,16 @@
else:
raise self._convert_error("compatible pointer", w_ob)
if self is not other:
- if not (self.can_cast_anything or other.can_cast_anything):
+ if self.is_void_ptr or other.is_void_ptr:
+ pass # cast from or to 'void *'
+ elif self.is_voidchar_ptr or other.is_voidchar_ptr:
+ space = self.space
+ msg = ("implicit cast from '%s' to '%s' "
+ "will be forbidden in the future (check that the types "
+ "are as you expect; use an explicit ffi.cast() if they "
+ "are correct)" % (other.name, self.name))
+ space.warn(space.wrap(msg), space.w_UserWarning, stacklevel=1)
+ else:
raise self._convert_error("compatible pointer", w_ob)
rffi.cast(rffi.CCHARPP, cdata)[0] = w_ob.unsafe_escaping_ptr()
@@ -165,8 +177,8 @@
class W_CTypePointer(W_CTypePtrBase):
- _attrs_ = ['is_file', 'cache_array_type', 'is_void_ptr', '_array_types']
- _immutable_fields_ = ['is_file', 'cache_array_type?', 'is_void_ptr']
+ _attrs_ = ['is_file', 'cache_array_type', '_array_types']
+ _immutable_fields_ = ['is_file', 'cache_array_type?']
kind = "pointer"
cache_array_type = None
is_nonfunc_pointer_or_array = True
@@ -181,6 +193,8 @@
self.is_file = (ctitem.name == "struct _IO_FILE" or
ctitem.name == "FILE")
self.is_void_ptr = isinstance(ctitem, ctypevoid.W_CTypeVoid)
+ self.is_voidchar_ptr = (self.is_void_ptr or
+ isinstance(ctitem, ctypeprim.W_CTypePrimitiveChar))
W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem)
def newp(self, w_init, allocator):
diff --git a/pypy/module/_cffi_backend/ctypevoid.py b/pypy/module/_cffi_backend/ctypevoid.py
--- a/pypy/module/_cffi_backend/ctypevoid.py
+++ b/pypy/module/_cffi_backend/ctypevoid.py
@@ -7,7 +7,6 @@
class W_CTypeVoid(W_CType):
_attrs_ = []
- cast_anything = True
kind = "void"
def __init__(self, space):
diff --git a/pypy/module/_cffi_backend/embedding.py b/pypy/module/_cffi_backend/embedding.py
--- a/pypy/module/_cffi_backend/embedding.py
+++ b/pypy/module/_cffi_backend/embedding.py
@@ -112,29 +112,7 @@
#define _WIN32_WINNT 0x0501
#include <windows.h>
-#define CFFI_INIT_HOME_PATH_MAX _MAX_PATH
static void _cffi_init(void);
-static void _cffi_init_error(const char *msg, const char *extra);
-
-static int _cffi_init_home(char *output_home_path)
-{
- HMODULE hModule = 0;
- DWORD res;
-
- GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
- GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
- (LPCTSTR)&_cffi_init, &hModule);
-
- if (hModule == 0 ) {
- _cffi_init_error("GetModuleHandleEx() failed", "");
- return -1;
- }
- res = GetModuleFileName(hModule, output_home_path, CFFI_INIT_HOME_PATH_MAX);
- if (res >= CFFI_INIT_HOME_PATH_MAX) {
- return -1;
- }
- return 0;
-}
static void _cffi_init_once(void)
{
@@ -155,28 +133,9 @@
else:
do_includes = r"""
-#include <dlfcn.h>
#include <pthread.h>
-#define CFFI_INIT_HOME_PATH_MAX PATH_MAX
static void _cffi_init(void);
-static void _cffi_init_error(const char *msg, const char *extra);
-
-static int _cffi_init_home(char *output_home_path)
-{
- Dl_info info;
- dlerror(); /* reset */
- if (dladdr(&_cffi_init, &info) == 0) {
- _cffi_init_error("dladdr() failed: ", dlerror());
- return -1;
- }
- if (realpath(info.dli_fname, output_home_path) == NULL) {
- perror("realpath() failed");
- _cffi_init_error("realpath() failed", "");
- return -1;
- }
- return 0;
-}
static void _cffi_init_once(void)
{
@@ -201,14 +160,10 @@
static void _cffi_init(void)
{
- char home[CFFI_INIT_HOME_PATH_MAX + 1];
-
rpython_startup_code();
RPyGilAllocate();
- if (_cffi_init_home(home) != 0)
- return;
- if (pypy_setup_home(home, 1) != 0) {
+ if (pypy_setup_home(NULL, 1) != 0) {
_cffi_init_error("pypy_setup_home() failed", "");
return;
}
diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py
--- a/pypy/module/_cffi_backend/handle.py
+++ b/pypy/module/_cffi_backend/handle.py
@@ -32,8 +32,8 @@
@unwrap_spec(w_cdata=cdataobj.W_CData)
def from_handle(space, w_cdata):
ctype = w_cdata.ctype
- if (not isinstance(ctype, ctypeptr.W_CTypePtrOrArray) or
- not ctype.can_cast_anything):
+ if (not isinstance(ctype, ctypeptr.W_CTypePointer) or
+ not ctype.is_voidchar_ptr):
raise oefmt(space.w_TypeError,
"expected a 'cdata' object with a 'void *' out of "
"new_handle(), got '%s'", ctype.name)
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.8.2", ("This test_c.py file is for testing a version"
+assert __version__ == "1.8.4", ("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,):
@@ -3665,3 +3665,27 @@
check_dir(pp, [])
check_dir(pp[0], ['a1', 'a2'])
check_dir(pp[0][0], ['a1', 'a2'])
+
+def test_char_pointer_conversion():
+ import warnings
+ assert __version__.startswith(("1.8", "1.9")), (
+ "consider turning the warning into an error")
+ BCharP = new_pointer_type(new_primitive_type("char"))
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ BVoidP = new_pointer_type(new_void_type())
+ z1 = cast(BCharP, 0)
+ z2 = cast(BIntP, 0)
+ z3 = cast(BVoidP, 0)
+ with warnings.catch_warnings(record=True) as w:
+ newp(new_pointer_type(BIntP), z1) # warn
+ assert len(w) == 1
+ newp(new_pointer_type(BVoidP), z1) # fine
+ assert len(w) == 1
+ newp(new_pointer_type(BCharP), z2) # warn
+ assert len(w) == 2
+ newp(new_pointer_type(BVoidP), z2) # fine
+ assert len(w) == 2
+ newp(new_pointer_type(BCharP), z3) # fine
+ assert len(w) == 2
+ newp(new_pointer_type(BIntP), z3) # fine
+ assert len(w) == 2
diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py b/pypy/module/_cffi_backend/test/test_ffi_obj.py
--- a/pypy/module/_cffi_backend/test/test_ffi_obj.py
+++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py
@@ -503,3 +503,15 @@
assert ffi.unpack(p+1, 7) == b"bc\x00def\x00"
p = ffi.new("int[]", [-123456789])
assert ffi.unpack(p, 1) == [-123456789]
+
+ def test_bug_1(self):
+ import _cffi_backend as _cffi1_backend
+ ffi = _cffi1_backend.FFI()
+ q = ffi.new("char[]", b"abcd")
+ p = ffi.cast("char(*)(void)", q)
+ raises(TypeError, ffi.string, p)
+
+ def test_negative_array_size(self):
+ import _cffi_backend as _cffi1_backend
+ ffi = _cffi1_backend.FFI()
+ raises(ffi.error, ffi.cast, "int[-5]", 0)
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
@@ -8,7 +8,7 @@
@unwrap_spec(cdef=str, module_name=str, source=str)
def prepare(space, cdef, module_name, source, w_includes=None,
- w_extra_source=None):
+ w_extra_source=None, w_min_version=None):
try:
import cffi
from cffi import FFI # <== the system one, which
@@ -16,8 +16,13 @@
from cffi import ffiplatform
except ImportError:
py.test.skip("system cffi module not found or older than 1.0.0")
- if cffi.__version_info__ < (1, 4, 0):
- py.test.skip("system cffi module needs to be at least 1.4.0")
+ if w_min_version is None:
+ min_version = (1, 4, 0)
+ else:
+ min_version = tuple(space.unwrap(w_min_version))
+ if cffi.__version_info__ < min_version:
+ py.test.skip("system cffi module needs to be at least %s, got %s" % (
+ min_version, cffi.__version_info__))
space.appexec([], """():
import _cffi_backend # force it to be initialized
""")
@@ -1790,3 +1795,28 @@
"void f(void) { }")
assert lib.f.__get__(42) is lib.f
assert lib.f.__get__(42, int) is lib.f
+
+ def test_typedef_array_dotdotdot(self):
+ ffi, lib = self.prepare("""
+ typedef int foo_t[...], bar_t[...];
+ int gv[...];
+ typedef int mat_t[...][...];
+ typedef int vmat_t[][...];
+ """,
+ "test_typedef_array_dotdotdot", """
+ typedef int foo_t[50], bar_t[50];
+ int gv[23];
+ typedef int mat_t[6][7];
+ typedef int vmat_t[][8];
+ """, min_version=(1, 8, 4))
+ assert ffi.sizeof("foo_t") == 50 * ffi.sizeof("int")
+ assert ffi.sizeof("bar_t") == 50 * ffi.sizeof("int")
+ assert len(ffi.new("foo_t")) == 50
+ assert len(ffi.new("bar_t")) == 50
+ assert ffi.sizeof(lib.gv) == 23 * ffi.sizeof("int")
+ assert ffi.sizeof("mat_t") == 6 * 7 * ffi.sizeof("int")
+ assert len(ffi.new("mat_t")) == 6
+ assert len(ffi.new("mat_t")[3]) == 7
+ raises(ffi.error, ffi.sizeof, "vmat_t")
+ p = ffi.new("vmat_t", 4)
+ assert ffi.sizeof(p[3]) == 8 * ffi.sizeof("int")
diff --git a/pypy/module/_collections/interp_deque.py b/pypy/module/_collections/interp_deque.py
--- a/pypy/module/_collections/interp_deque.py
+++ b/pypy/module/_collections/interp_deque.py
@@ -6,6 +6,7 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.error import OperationError, oefmt
from rpython.rlib.debug import check_nonneg
+from rpython.rlib.objectmodel import specialize
# A `dequeobject` is composed of a doubly-linked list of `block` nodes.
@@ -316,12 +317,12 @@
w_currently_in_repr = ec._py_repr = space.newdict()
return dequerepr(space, w_currently_in_repr, space.wrap(self))
+ @specialize.arg(2)
def compare(self, w_other, op):
space = self.space
if not isinstance(w_other, W_Deque):
return space.w_NotImplemented
return space.compare_by_iteration(space.wrap(self), w_other, op)
- compare._annspecialcase_ = 'specialize:arg(2)'
def lt(self, w_other):
return self.compare(w_other, 'lt')
diff --git a/pypy/module/_csv/interp_reader.py b/pypy/module/_csv/interp_reader.py
--- a/pypy/module/_csv/interp_reader.py
+++ b/pypy/module/_csv/interp_reader.py
@@ -1,4 +1,5 @@
from rpython.rlib.rstring import StringBuilder
+from rpython.rlib import objectmodel
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.gateway import unwrap_spec
@@ -25,12 +26,12 @@
def iter_w(self):
return self.space.wrap(self)
+ @objectmodel.dont_inline
def error(self, msg):
space = self.space
w_module = space.getbuiltinmodule('_csv')
w_error = space.getattr(w_module, space.wrap('Error'))
raise oefmt(w_error, "line %d: %s", self.line_num, msg)
- error._dont_inline_ = True
def add_char(self, field_builder, c):
assert field_builder is not None
diff --git a/pypy/module/_csv/interp_writer.py b/pypy/module/_csv/interp_writer.py
--- a/pypy/module/_csv/interp_writer.py
+++ b/pypy/module/_csv/interp_writer.py
@@ -1,4 +1,5 @@
from rpython.rlib.rstring import StringBuilder
+from rpython.rlib import objectmodel
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.error import OperationError
from pypy.interpreter.typedef import TypeDef, interp2app
@@ -21,12 +22,12 @@
special += dialect.quotechar
self.special_characters = special
+ @objectmodel.dont_inline
def error(self, msg):
space = self.space
w_module = space.getbuiltinmodule('_csv')
w_error = space.getattr(w_module, space.wrap('Error'))
raise OperationError(w_error, space.wrap(msg))
- error._dont_inline_ = True
def writerow(self, w_fields):
"""Construct and write a CSV record from a sequence of fields.
diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py
--- a/pypy/module/_lsprof/interp_lsprof.py
+++ b/pypy/module/_lsprof/interp_lsprof.py
@@ -7,7 +7,7 @@
from pypy.interpreter.typedef import (TypeDef, GetSetProperty,
interp_attrproperty)
from rpython.rlib import jit
-from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.objectmodel import we_are_translated, always_inline
from rpython.rlib.rtimer import read_timestamp, _is_64_bit
from rpython.rtyper.lltypesystem import rffi, lltype
from rpython.translator.tool.cbuild import ExternalCompilationInfo
@@ -256,7 +256,7 @@
return w_frame.wrap_string(space)
return w_frame # actually a PyCode object
-
+ at always_inline
def prepare_spec(space, w_arg):
if isinstance(w_arg, Method):
return (w_arg.w_function, w_arg.w_class)
@@ -264,8 +264,6 @@
return (w_arg, None)
else:
return (None, space.type(w_arg))
-prepare_spec._always_inline_ = True
-
def lsprof_call(space, w_self, frame, event, w_arg):
assert isinstance(w_self, W_Profiler)
diff --git a/pypy/module/_pypyjson/interp_decoder.py b/pypy/module/_pypyjson/interp_decoder.py
--- a/pypy/module/_pypyjson/interp_decoder.py
+++ b/pypy/module/_pypyjson/interp_decoder.py
@@ -1,6 +1,6 @@
import sys
from rpython.rlib.rstring import StringBuilder
-from rpython.rlib.objectmodel import specialize
+from rpython.rlib.objectmodel import specialize, always_inline
from rpython.rlib import rfloat, runicode
from rpython.rtyper.lltypesystem import lltype, rffi
from pypy.interpreter.error import oefmt
@@ -188,6 +188,7 @@
self.pos = i
return self.space.call_function(self.space.w_int, self.space.wrap(s))
+ @always_inline
def parse_integer(self, i):
"Parse a decimal number with an optional minus sign"
sign = 1
@@ -218,7 +219,6 @@
# overflowed
ovf_maybe = (count >= OVF_DIGITS)
return i, ovf_maybe, sign * intval
- parse_integer._always_inline_ = True
def decode_array(self, i):
w_list = self.space.newlist([])
diff --git a/pypy/module/_pypyjson/targetjson.py b/pypy/module/_pypyjson/targetjson.py
--- a/pypy/module/_pypyjson/targetjson.py
+++ b/pypy/module/_pypyjson/targetjson.py
@@ -6,6 +6,7 @@
import time
from pypy.interpreter.error import OperationError
from pypy.module._pypyjson.interp_decoder import loads
+from rpython.rlib.objectmodel import specialize, dont_inline
## MSG = open('msg.json').read()
@@ -68,11 +69,11 @@
assert isinstance(w_x, W_String)
return w_x.strval
+ @dont_inline
def call_method(self, obj, name, arg):
assert name == 'append'
assert isinstance(obj, W_List)
obj.listval.append(arg)
- call_method._dont_inline_ = True
def call_function(self, w_func, *args_w):
return self.w_None # XXX
@@ -91,6 +92,7 @@
def wrapfloat(self, x):
return W_Float(x)
+ @specialize.argtype(1)
def wrap(self, x):
if isinstance(x, int):
return W_Int(x)
@@ -100,7 +102,6 @@
## assert False
else:
return W_Unicode(unicode(x))
- wrap._annspecialcase_ = "specialize:argtype(1)"
fakespace = FakeSpace()
diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py
--- a/pypy/module/_rawffi/interp_rawffi.py
+++ b/pypy/module/_rawffi/interp_rawffi.py
@@ -9,6 +9,7 @@
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.rtyper.tool import rffi_platform
from rpython.rlib.unroll import unrolling_iterable
+from rpython.rlib.objectmodel import specialize
import rpython.rlib.rposix as rposix
_MS_WINDOWS = os.name == "nt"
@@ -255,6 +256,7 @@
_ARM = rffi_platform.getdefined('__arm__', '')
+ at specialize.arg(2)
def read_ptr(ptr, ofs, TP):
T = lltype.Ptr(rffi.CArray(TP))
for c in unroll_letters_for_floats:
@@ -274,8 +276,8 @@
return ptr_val
else:
return rffi.cast(T, ptr)[ofs]
-read_ptr._annspecialcase_ = 'specialize:arg(2)'
+ at specialize.argtype(2)
def write_ptr(ptr, ofs, value):
TP = lltype.typeOf(value)
T = lltype.Ptr(rffi.CArray(TP))
@@ -296,7 +298,6 @@
return
else:
rffi.cast(T, ptr)[ofs] = value
-write_ptr._annspecialcase_ = 'specialize:argtype(2)'
def segfault_exception(space, reason):
w_mod = space.getbuiltinmodule("_rawffi")
@@ -374,14 +375,15 @@
def getrawsize(self):
raise NotImplementedError("abstract base class")
+ at specialize.arg(0)
def unwrap_truncate_int(TP, space, w_arg):
if space.isinstance_w(w_arg, space.w_int):
return rffi.cast(TP, space.int_w(w_arg))
else:
return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask())
-unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)'
+ at specialize.arg(1)
def unwrap_value(space, push_func, add_arg, argdesc, letter, w_arg):
if letter in TYPEMAP_PTR_LETTERS:
# check for NULL ptr
@@ -422,10 +424,10 @@
return
else:
raise oefmt(space.w_TypeError, "cannot directly write value")
-unwrap_value._annspecialcase_ = 'specialize:arg(1)'
ll_typemap_iter = unrolling_iterable(LL_TYPEMAP.items())
+ at specialize.arg(1)
def wrap_value(space, func, add_arg, argdesc, letter):
for c, ll_type in ll_typemap_iter:
if letter == c:
@@ -437,7 +439,6 @@
else:
return space.wrap(func(add_arg, argdesc, ll_type))
raise oefmt(space.w_TypeError, "cannot directly read value")
-wrap_value._annspecialcase_ = 'specialize:arg(1)'
NARROW_INTEGER_TYPES = 'cbhiBIH?'
diff --git a/pypy/module/_rawffi/structure.py b/pypy/module/_rawffi/structure.py
--- a/pypy/module/_rawffi/structure.py
+++ b/pypy/module/_rawffi/structure.py
@@ -18,6 +18,7 @@
from rpython.rlib.rarithmetic import intmask, signedtype, r_uint, \
r_ulonglong
from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rlib.objectmodel import specialize
import sys
IS_BIG_ENDIAN = sys.byteorder == 'big'
@@ -284,6 +285,7 @@
def NUM_BITS(x):
return x >> 16
+ at specialize.arg(1)
def BIT_MASK(x, ll_t):
if ll_t is lltype.SignedLongLong or ll_t is lltype.UnsignedLongLong:
one = r_ulonglong(1)
@@ -291,8 +293,8 @@
one = r_uint(1)
# to avoid left shift by x == sizeof(ll_t)
return (((one << (x - 1)) - 1) << 1) + 1
-BIT_MASK._annspecialcase_ = 'specialize:arg(1)'
+ at specialize.argtype(2)
def push_field(self, num, value):
ptr = rffi.ptradd(self.ll_buffer, self.shape.ll_positions[num])
TP = lltype.typeOf(value)
@@ -313,8 +315,8 @@
value = rffi.cast(TP, current)
break
write_ptr(ptr, 0, value)
-push_field._annspecialcase_ = 'specialize:argtype(2)'
+ at specialize.arg(2)
def cast_pos(self, i, ll_t):
pos = rffi.ptradd(self.ll_buffer, self.shape.ll_positions[i])
value = read_ptr(pos, 0, ll_t)
@@ -337,7 +339,6 @@
value = rffi.cast(ll_t, value)
break
return value
-cast_pos._annspecialcase_ = 'specialize:arg(2)'
class W_StructureInstance(W_DataInstance):
def __init__(self, space, shape, address):
diff --git a/pypy/module/_warnings/interp_warnings.py b/pypy/module/_warnings/interp_warnings.py
--- a/pypy/module/_warnings/interp_warnings.py
+++ b/pypy/module/_warnings/interp_warnings.py
@@ -248,6 +248,10 @@
if space.isinstance_w(w_message, space.w_Warning):
w_text = space.str(w_message)
w_category = space.type(w_message)
+ elif (not space.isinstance_w(w_message, space.w_unicode) or
+ not space.isinstance_w(w_message, space.w_str)):
+ w_text = space.str(w_message)
+ w_message = space.call_function(w_category, w_message)
else:
w_text = w_message
w_message = space.call_function(w_category, w_message)
diff --git a/pypy/module/_warnings/test/test_warnings.py b/pypy/module/_warnings/test/test_warnings.py
--- a/pypy/module/_warnings/test/test_warnings.py
+++ b/pypy/module/_warnings/test/test_warnings.py
@@ -11,6 +11,7 @@
import _warnings
_warnings.warn("some message", DeprecationWarning)
_warnings.warn("some message", Warning)
+ _warnings.warn(("some message",1), Warning)
def test_lineno(self):
import warnings, _warnings, sys
@@ -40,7 +41,10 @@
def test_show_source_line(self):
import warnings
import sys, StringIO
- from test.warning_tests import inner
+ try:
+ from test.warning_tests import inner
+ except ImportError:
+ skip('no test, -A on cpython?')
# With showarning() missing, make sure that output is okay.
del warnings.showwarning
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -34,21 +34,21 @@
if typecode == tc:
a = space.allocate_instance(types[tc].w_class, w_cls)
a.__init__(space)
-
- if len(__args__.arguments_w) > 0:
- w_initializer = __args__.arguments_w[0]
- if space.type(w_initializer) is space.w_str:
- a.descr_fromstring(space, w_initializer)
- elif space.type(w_initializer) is space.w_list:
- a.descr_fromlist(space, w_initializer)
- else:
- a.extend(w_initializer, True)
break
else:
raise oefmt(space.w_ValueError,
"bad typecode (must be c, b, B, u, h, H, i, I, l, L, f or "
"d)")
+ if len(__args__.arguments_w) > 0:
+ w_initializer = __args__.arguments_w[0]
+ w_initializer_type = space.type(w_initializer)
+ if w_initializer_type is space.w_str:
+ a.descr_fromstring(space, w_initializer)
+ elif w_initializer_type is space.w_list:
+ a.descr_fromlist(space, w_initializer)
+ else:
+ a.extend(w_initializer, True)
return a
diff --git a/pypy/module/cpyext/longobject.py b/pypy/module/cpyext/longobject.py
--- a/pypy/module/cpyext/longobject.py
+++ b/pypy/module/cpyext/longobject.py
@@ -6,7 +6,6 @@
from pypy.interpreter.error import OperationError
from pypy.module.cpyext.intobject import PyInt_AsUnsignedLongMask
from rpython.rlib.rbigint import rbigint
-from rpython.rlib.rarithmetic import intmask
PyLong_Check, PyLong_CheckExact = build_type_checkers("Long")
@@ -28,25 +27,25 @@
"""Return a new PyLongObject object from a C size_t, or NULL on
failure.
"""
- return space.wrap(val)
+ return space.newlong_from_rarith_int(val)
@cpython_api([rffi.LONGLONG], PyObject)
def PyLong_FromLongLong(space, val):
"""Return a new PyLongObject object from a C long long, or NULL
on failure."""
- return space.wrap(val)
+ return space.newlong_from_rarith_int(val)
@cpython_api([rffi.ULONG], PyObject)
def PyLong_FromUnsignedLong(space, val):
"""Return a new PyLongObject object from a C unsigned long, or
NULL on failure."""
- return space.wrap(val)
+ return space.newlong_from_rarith_int(val)
@cpython_api([rffi.ULONGLONG], PyObject)
def PyLong_FromUnsignedLongLong(space, val):
"""Return a new PyLongObject object from a C unsigned long long,
or NULL on failure."""
- return space.wrap(val)
+ return space.newlong_from_rarith_int(val)
@cpython_api([PyObject], rffi.ULONG, error=-1)
def PyLong_AsUnsignedLong(space, w_long):
@@ -203,7 +202,10 @@
can be retrieved from the resulting value using PyLong_AsVoidPtr().
If the integer is larger than LONG_MAX, a positive long integer is returned."""
- return space.wrap(rffi.cast(ADDR, p))
+ value = rffi.cast(ADDR, p) # signed integer
+ if value < 0:
+ return space.newlong_from_rarith_int(rffi.cast(lltype.Unsigned, p))
+ return space.wrap(value)
@cpython_api([PyObject], rffi.VOIDP, error=lltype.nullptr(rffi.VOIDP.TO))
def PyLong_AsVoidPtr(space, w_long):
diff --git a/pypy/module/cpyext/memoryobject.py b/pypy/module/cpyext/memoryobject.py
--- a/pypy/module/cpyext/memoryobject.py
+++ b/pypy/module/cpyext/memoryobject.py
@@ -53,10 +53,7 @@
else:
n = len(fmt)
for i in range(n):
- if ord(fmt[i]) > 255:
- view.c_format[i] = '*'
- else:
- view.c_format[i] = fmt[i]
+ view.c_format[i] = fmt[i]
view.c_format[n] = '\x00'
shape = buf.getshape()
strides = buf.getstrides()
diff --git a/pypy/module/cpyext/pytraceback.py b/pypy/module/cpyext/pytraceback.py
--- a/pypy/module/cpyext/pytraceback.py
+++ b/pypy/module/cpyext/pytraceback.py
@@ -5,7 +5,6 @@
from pypy.module.cpyext.pyobject import (
PyObject, make_ref, from_ref, Py_DecRef, make_typedescr)
from pypy.module.cpyext.frameobject import PyFrameObject
-from rpython.rlib.unroll import unrolling_iterable
from pypy.interpreter.error import OperationError
from pypy.interpreter.pytraceback import PyTraceback
from pypy.interpreter import pycode
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -214,7 +214,9 @@
i = space.int_w(space.index(args_w[0]))
j = space.int_w(space.index(args_w[1]))
w_y = args_w[2]
- return space.wrap(generic_cpy_call(space, func_target, w_self, i, j, w_y))
+ res = generic_cpy_call(space, func_target, w_self, i, j, w_y)
+ if rffi.cast(lltype.Signed, res) == -1:
+ space.fromcache(State).check_and_raise_exception(always=True)
def wrap_lenfunc(space, w_self, w_args, func):
func_len = rffi.cast(lenfunc, func)
@@ -296,7 +298,10 @@
def wrap_hashfunc(space, w_self, w_args, func):
func_target = rffi.cast(hashfunc, func)
check_num_args(space, w_args, 0)
- return space.wrap(generic_cpy_call(space, func_target, w_self))
+ res = generic_cpy_call(space, func_target, w_self)
+ if res == -1:
+ space.fromcache(State).check_and_raise_exception(always=True)
+ return space.wrap(res)
class CPyBuffer(Buffer):
# Similar to Py_buffer
diff --git a/pypy/module/cpyext/test/foo3.c b/pypy/module/cpyext/test/foo3.c
--- a/pypy/module/cpyext/test/foo3.c
+++ b/pypy/module/cpyext/test/foo3.c
@@ -4,9 +4,7 @@
PyObject* foo3type_tp_new(PyTypeObject* metatype, PyObject* args, PyObject* kwds)
{
PyObject* newType;
- /*printf("in foo3type_tp_new, preprocessing...\n"); */
newType = PyType_Type.tp_new(metatype, args, kwds);
- /*printf("in foo3type_tp_new, postprocessing...\n"); */
return newType;
}
@@ -81,4 +79,5 @@
return;
if (PyDict_SetItemString(d, "footype", (PyObject *)&footype) < 0)
return;
+ Py_INCREF(&footype);
}
diff --git a/pypy/module/cpyext/test/test_arraymodule.py b/pypy/module/cpyext/test/test_arraymodule.py
--- a/pypy/module/cpyext/test/test_arraymodule.py
+++ b/pypy/module/cpyext/test/test_arraymodule.py
@@ -49,6 +49,7 @@
assert arr.tolist() == [1, 21, 22, 23, 4]
del arr[slice(1, 3)]
assert arr.tolist() == [1, 23, 4]
+ raises(TypeError, 'arr[slice(1, 3)] = "abc"')
def test_buffer(self):
import sys
diff --git a/pypy/module/cpyext/test/test_longobject.py b/pypy/module/cpyext/test/test_longobject.py
--- a/pypy/module/cpyext/test/test_longobject.py
+++ b/pypy/module/cpyext/test/test_longobject.py
@@ -1,5 +1,6 @@
import sys, py
from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib.rarithmetic import maxint
from pypy.objspace.std.intobject import W_IntObject
from pypy.objspace.std.longobject import W_LongObject
from pypy.module.cpyext.test.test_api import BaseApiTest
@@ -8,18 +9,20 @@
class TestLongObject(BaseApiTest):
def test_FromLong(self, space, api):
- value = api.PyLong_FromLong(3)
- assert isinstance(value, W_LongObject)
- assert space.unwrap(value) == 3
+ w_value = api.PyLong_FromLong(3)
+ assert isinstance(w_value, W_LongObject)
+ assert space.unwrap(w_value) == 3
- value = api.PyLong_FromLong(sys.maxint)
- assert isinstance(value, W_LongObject)
- assert space.unwrap(value) == sys.maxint
+ w_value = api.PyLong_FromLong(sys.maxint)
+ assert isinstance(w_value, W_LongObject)
+ assert space.unwrap(w_value) == sys.maxint
def test_aslong(self, space, api):
w_value = api.PyLong_FromLong((sys.maxint - 1) / 2)
+ assert isinstance(w_value, W_LongObject)
w_value = space.mul(w_value, space.wrap(2))
+ assert isinstance(w_value, W_LongObject)
value = api.PyLong_AsLong(w_value)
assert value == (sys.maxint - 1)
@@ -35,12 +38,16 @@
def test_as_ssize_t(self, space, api):
w_value = space.newlong(2)
+ assert isinstance(w_value, W_LongObject)
value = api.PyLong_AsSsize_t(w_value)
assert value == 2
- assert space.eq_w(w_value, api.PyLong_FromSsize_t(2))
+ w_val2 = api.PyLong_FromSsize_t(2)
+ assert isinstance(w_val2, W_LongObject)
+ assert space.eq_w(w_value, w_val2)
def test_fromdouble(self, space, api):
w_value = api.PyLong_FromDouble(-12.74)
+ assert isinstance(w_value, W_LongObject)
assert space.unwrap(w_value) == -12
assert api.PyLong_AsDouble(w_value) == -12
@@ -102,9 +109,26 @@
lltype.free(overflow, flavor='raw')
def test_as_voidptr(self, space, api):
+ # CPython returns an int (not a long) depending on the value
+ # passed to PyLong_FromVoidPtr(). In all cases, NULL becomes
+ # the int 0.
w_l = api.PyLong_FromVoidPtr(lltype.nullptr(rffi.VOIDP.TO))
- assert space.unwrap(w_l) == 0L
+ assert space.is_w(space.type(w_l), space.w_int)
+ assert space.unwrap(w_l) == 0
assert api.PyLong_AsVoidPtr(w_l) == lltype.nullptr(rffi.VOIDP.TO)
+ # Positive values also return an int (assuming, like always in
+ # PyPy, that an int is big enough to store any pointer).
+ p = rffi.cast(rffi.VOIDP, maxint)
+ w_l = api.PyLong_FromVoidPtr(p)
+ assert space.is_w(space.type(w_l), space.w_int)
+ assert space.unwrap(w_l) == maxint
+ assert api.PyLong_AsVoidPtr(w_l) == p
+ # Negative values always return a long.
+ p = rffi.cast(rffi.VOIDP, -maxint-1)
+ w_l = api.PyLong_FromVoidPtr(p)
+ assert space.is_w(space.type(w_l), space.w_long)
+ assert space.unwrap(w_l) == maxint+1
+ assert api.PyLong_AsVoidPtr(w_l) == p
def test_sign_and_bits(self, space, api):
if space.is_true(space.lt(space.sys.get('version_info'),
@@ -128,23 +152,58 @@
module = self.import_extension('foo', [
("from_unsignedlong", "METH_NOARGS",
"""
- return PyLong_FromUnsignedLong((unsigned long)-1);
+ PyObject * obj;
+ obj = PyLong_FromUnsignedLong((unsigned long)-1);
+ if (obj->ob_type != &PyLong_Type)
+ {
+ Py_DECREF(obj);
+ PyErr_SetString(PyExc_ValueError,
+ "PyLong_FromLongLong did not return PyLongObject");
+ return NULL;
+ }
+ return obj;
""")])
import sys
assert module.from_unsignedlong() == 2 * sys.maxint + 1
def test_fromlonglong(self):
module = self.import_extension('foo', [
- ("from_longlong", "METH_NOARGS",
+ ("from_longlong", "METH_VARARGS",
"""
- return PyLong_FromLongLong((long long)-1);
+ int val;
+ PyObject * obj;
+ if (!PyArg_ParseTuple(args, "i", &val))
+ return NULL;
+ obj = PyLong_FromLongLong((long long)val);
+ if (obj->ob_type != &PyLong_Type)
+ {
+ Py_DECREF(obj);
+ PyErr_SetString(PyExc_ValueError,
+ "PyLong_FromLongLong did not return PyLongObject");
+ return NULL;
+ }
+ return obj;
"""),
- ("from_unsignedlonglong", "METH_NOARGS",
+ ("from_unsignedlonglong", "METH_VARARGS",
"""
- return PyLong_FromUnsignedLongLong((unsigned long long)-1);
+ int val;
+ PyObject * obj;
+ if (!PyArg_ParseTuple(args, "i", &val))
+ return NULL;
+ obj = PyLong_FromUnsignedLongLong((long long)val);
+ if (obj->ob_type != &PyLong_Type)
+ {
+ Py_DECREF(obj);
+ PyErr_SetString(PyExc_ValueError,
+ "PyLong_FromLongLong did not return PyLongObject");
+ return NULL;
+ }
+ return obj;
""")])
- assert module.from_longlong() == -1
- assert module.from_unsignedlonglong() == (1<<64) - 1
+ assert module.from_longlong(-1) == -1
+ assert module.from_longlong(0) == 0
+ assert module.from_unsignedlonglong(0) == 0
+ assert module.from_unsignedlonglong(-1) == (1<<64) - 1
def test_from_size_t(self):
module = self.import_extension('foo', [
@@ -232,10 +291,15 @@
("has_sub", "METH_NOARGS",
"""
PyObject *ret, *obj = PyLong_FromLong(42);
- if (obj->ob_type->tp_as_number->nb_subtract)
- ret = obj->ob_type->tp_as_number->nb_subtract(obj, obj);
+ if (obj->ob_type != &PyLong_Type)
+ ret = PyLong_FromLong(-2);
else
- ret = PyLong_FromLong(-1);
+ {
+ if (obj->ob_type->tp_as_number->nb_subtract)
+ ret = obj->ob_type->tp_as_number->nb_subtract(obj, obj);
+ else
+ ret = PyLong_FromLong(-1);
+ }
Py_DECREF(obj);
return ret;
"""),
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -961,7 +961,6 @@
def test_tp_new_in_subclass_of_type(self):
module = self.import_module(name='foo3')
- #print('calling module.footype()...')
module.footype("X", (object,), {})
def test_app_subclass_of_c_type(self):
diff --git a/pypy/module/math/interp_math.py b/pypy/module/math/interp_math.py
--- a/pypy/module/math/interp_math.py
+++ b/pypy/module/math/interp_math.py
@@ -2,6 +2,7 @@
import sys
from rpython.rlib import rfloat
+from rpython.rlib.objectmodel import specialize
from pypy.interpreter.error import OperationError, oefmt
class State:
@@ -17,6 +18,7 @@
else:
return space.float_w(space.float(w_x))
+ at specialize.arg(1)
def math1(space, f, w_x):
x = _get_double(space, w_x)
try:
@@ -26,8 +28,8 @@
except ValueError:
raise oefmt(space.w_ValueError, "math domain error")
return space.wrap(y)
-math1._annspecialcase_ = 'specialize:arg(1)'
+ at specialize.arg(1)
def math1_w(space, f, w_x):
x = _get_double(space, w_x)
try:
@@ -37,8 +39,8 @@
except ValueError:
raise oefmt(space.w_ValueError, "math domain error")
return r
-math1_w._annspecialcase_ = 'specialize:arg(1)'
+ at specialize.arg(1)
def math2(space, f, w_x, w_snd):
x = _get_double(space, w_x)
snd = _get_double(space, w_snd)
@@ -49,7 +51,6 @@
except ValueError:
raise oefmt(space.w_ValueError, "math domain error")
return space.wrap(r)
-math2._annspecialcase_ = 'specialize:arg(1)'
def trunc(space, w_x):
"""Truncate x."""
diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py
--- a/pypy/module/mmap/interp_mmap.py
+++ b/pypy/module/mmap/interp_mmap.py
@@ -2,7 +2,7 @@
More information about the pypy-commit
mailing list