Commit 2fb2bdf2 authored by Matti Picus's avatar Matti Picus
Browse files

merge default into branch

--HG--
branch : buffer-interface2
Metadata-Version: 1.1
Name: cffi
Version: 1.8.2
Version: 1.8.3
Summary: Foreign Function Interface for Python calling C code.
Home-page: http://cffi.readthedocs.org
Author: Armin Rigo, Maciej Fijalkowski
......
......@@ -4,8 +4,8 @@ __all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError',
from .api import FFI, CDefError, FFIError
from .ffiplatform import VerificationError, VerificationMissing
__version__ = "1.8.2"
__version_info__ = (1, 8, 2)
__version__ = "1.8.3"
__version_info__ = (1, 8, 3)
# 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__
......
......@@ -233,7 +233,7 @@ static int _cffi_initialize_python(void)
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.3"
"\n_cffi_backend module: ", f);
modules = PyImport_GetModuleDict();
mod = PyDict_GetItemString(modules, "_cffi_backend");
......
......@@ -3,3 +3,14 @@ arguments with which to call pypy-c (and in general the translated
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.
......@@ -449,6 +449,27 @@ Miscellaneous
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/
......@@ -16,3 +16,8 @@ in numpypy
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.
......@@ -239,6 +239,10 @@ class PyPyTarget(object):
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)
......
......@@ -1986,6 +1986,7 @@ ObjSpace.ExceptionTable = [
'ZeroDivisionError',
'RuntimeWarning',
'PendingDeprecationWarning',
'UserWarning',
]
if sys.platform.startswith("win"):
......
......@@ -63,7 +63,7 @@ class GeneratorIterator(W_Root):
"""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)
......
......@@ -264,25 +264,22 @@ class PyFrame(W_Root):
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
......
......@@ -57,12 +57,14 @@ class AppTestGenerator:
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 @@ class AppTestGenerator:
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():
......
......@@ -562,3 +562,21 @@ class AppTestPyFrame:
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']
......@@ -3,7 +3,7 @@ from pypy.interpreter.mixedmodule import MixedModule
from rpython.rlib import rdynload, clibffi, entrypoint
from rpython.rtyper.lltypesystem import rffi
VERSION = "1.8.2"
VERSION = "1.8.3"
FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI
try:
......
......@@ -11,7 +11,7 @@ from rpython.rtyper.lltypesystem import lltype, rffi
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 @@ class W_CTypeArray(W_CTypePtrOrArray):
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
......
......@@ -35,8 +35,7 @@ class W_CTypeFunc(W_CTypePtrBase):
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 @@ class W_CTypeFunc(W_CTypePtrBase):
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)
......
......@@ -19,7 +19,6 @@ class W_CType(W_Root):
# 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
......
......@@ -120,7 +120,6 @@ class W_CTypePrimitiveCharOrUniChar(W_CTypePrimitive):
class W_CTypePrimitiveChar(W_CTypePrimitiveCharOrUniChar):
_attrs_ = []
cast_anything = True
def cast_to_int(self, cdata):
return self.space.wrap(ord(cdata[0]))
......
......@@ -14,12 +14,11 @@ from pypy.module._cffi_backend.ctypeobj import W_CType
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 @@ class W_CTypePtrOrArray(W_CType):
# - 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_CTypePtrOrArray(W_CType):
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 @@ class W_CTypePtrBase(W_CTypePtrOrArray):
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_CTypePtrBase(W_CTypePtrOrArray):
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 @@ class W_CTypePointer(W_CTypePtrBase):
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):
......
......@@ -7,7 +7,6 @@ from pypy.module._cffi_backend.ctypeobj import W_CType
class W_CTypeVoid(W_CType):
_attrs_ = []
cast_anything = True
kind = "void"
def __init__(self, space):
......
......@@ -32,8 +32,8 @@ def newp_handle(space, w_ctype, w_x):
@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)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment