Author: Armin Rigo <ar...@tunes.org> Branch: py3.5 Changeset: r90047:88164726e74b Date: 2017-02-11 15:31 +0100 http://bitbucket.org/pypy/pypy/changeset/88164726e74b/
Log: hg merge default diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py --- a/lib_pypy/cffi/api.py +++ b/lib_pypy/cffi/api.py @@ -462,7 +462,12 @@ field or array item in the structure or array, recursively in case of nested structures. """ - ctype = self._backend.typeof(cdata) + try: + ctype = self._backend.typeof(cdata) + except TypeError: + if '__addressof__' in type(cdata).__dict__: + return type(cdata).__addressof__(cdata, *fields_or_indexes) + raise if fields_or_indexes: ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes) else: @@ -775,10 +780,7 @@ key = 'function ' + name tp, _ = ffi._parser._declarations[key] BType = ffi._get_cached_btype(tp) - try: - value = backendlib.load_function(BType, name) - except KeyError as e: - raise AttributeError('%s: %s' % (name, e)) + value = backendlib.load_function(BType, name) library.__dict__[name] = value # def accessor_variable(name): @@ -791,6 +793,21 @@ lambda self: read_variable(BType, name), lambda self, value: write_variable(BType, name, value))) # + def addressof_var(name): + try: + return addr_variables[name] + except KeyError: + with ffi._lock: + if name not in addr_variables: + key = 'variable ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + if BType.kind != 'array': + BType = model.pointer_cache(ffi, BType) + p = backendlib.load_function(BType, name) + addr_variables[name] = p + return addr_variables[name] + # def accessor_constant(name): raise NotImplementedError("non-integer constant '%s' cannot be " "accessed from a dlopen() library" % (name,)) @@ -800,6 +817,7 @@ # accessors = {} accessors_version = [False] + addr_variables = {} # def update_accessors(): if accessors_version[0] is ffi._cdef_version: @@ -850,6 +868,18 @@ with ffi._lock: update_accessors() return accessors.keys() + def __addressof__(self, name): + if name in library.__dict__: + return library.__dict__[name] + if name in FFILibrary.__dict__: + return addressof_var(name) + make_accessor(name) + if name in library.__dict__: + return library.__dict__[name] + if name in FFILibrary.__dict__: + return addressof_var(name) + raise AttributeError("cffi library has no function or " + "global variable named '%s'" % (name,)) # if libname is not None: try: diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info --- a/lib_pypy/greenlet.egg-info +++ b/lib_pypy/greenlet.egg-info @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: greenlet -Version: 0.4.11 +Version: 0.4.12 Summary: Lightweight in-process concurrent programming Home-page: https://github.com/python-greenlet/greenlet Author: Ralf Schmitt (for CPython), PyPy team diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py --- a/lib_pypy/greenlet.py +++ b/lib_pypy/greenlet.py @@ -2,7 +2,7 @@ import __pypy__ import _continuation -__version__ = "0.4.11" +__version__ = "0.4.12" # ____________________________________________________________ # Exceptions diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst --- a/pypy/doc/project-ideas.rst +++ b/pypy/doc/project-ideas.rst @@ -38,6 +38,21 @@ .. _mailing list: http://mail.python.org/mailman/listinfo/pypy-dev +Explicit typing in RPython +-------------------------- + +RPython is mostly based around type inference, but there are many cases where +specifying types explicitly is useful. We would like to be able to optionally +specify the exact types of the arguments to any function. We already have +solutions in that space, ``@rpython.rlib.objectmodel.enforceargs`` and +``@rpython.rlib.signature.signature``, but they are inconvenient and limited. +For instance, they do not easily allow to express the type "dict with ints as +keys and lists of instances of Foo as values". + +Additionally, we would like to be able to specify the types of instance +attributes. Unlike the function case, this is likely to require some +refactoring of the annotator. + Make bytearray type fast ------------------------ @@ -176,28 +191,33 @@ * `hg` -Optimising cpyext (CPython C-API compatibility layer) ------------------------------------------------------ - -A lot of work has gone into PyPy's implementation of CPython's C-API over -the last years to let it reach a practical level of compatibility, so that -C extensions for CPython work on PyPy without major rewrites. However, -there are still many edges and corner cases where it misbehaves. - -The objective of this project is to fix bugs in cpyext and to optimise -several performance critical parts of it, such as the reference counting -support and other heavily used C-API functions. The net result would be to -have CPython extensions run much faster on PyPy than they currently do, or -to make them work at all if they currently don't. A part of this work would -be to get cpyext into a shape where it supports running Cython generated -extensions. - ====================================== Make more python modules pypy-friendly ====================================== -Work has been started on a few popular python packages. Here is a partial -list of good work that needs to be finished: +A lot of work has gone into PyPy's implementation of CPython's C-API, cpyext, +over the last years to let it reach a practical level of compatibility, so that +C extensions for CPython work on PyPy without major rewrites. However, there +are still many edges and corner cases where it misbehaves. + +For any popular extension that does not already advertise full PyPy +compatibility, it would thus be useful to take a close look at it in order to +make it fully compatible with PyPy. The general process is something like: + +* Run the extension's tests on PyPy and look at the test failures. +* Some of the failures may be solved by identifying cases where the extension + relies on undocumented or internal details of CPython, and rewriting the + relevant code to follow documented best practices. Open issues and send pull + requests as appropriate given the extension's development process. +* Other failures may highlight incompatibilities between cpyext and CPython. + Please report them to us and try to fix them. +* Run benchmarks, either provided by the extension developers or created by + you. Any case where PyPy is significantly slower than CPython is to be + considered a bug and solved as above. + +Alternatively, an approach we used to recommend was to rewrite C extensions +using more pypy-friendly technologies, e.g. cffi. Here is a partial list of +good work that needs to be finished: **matplotlib** https://github.com/mattip/matplotlib @@ -223,5 +243,3 @@ **pyopengl** https://bitbucket.org/duangle/pyopengl-cffi Status: unknown - - diff --git a/pypy/module/_cffi_backend/libraryobj.py b/pypy/module/_cffi_backend/libraryobj.py --- a/pypy/module/_cffi_backend/libraryobj.py +++ b/pypy/module/_cffi_backend/libraryobj.py @@ -40,25 +40,22 @@ @unwrap_spec(w_ctype=W_CType, name=str) def load_function(self, w_ctype, name): - from pypy.module._cffi_backend import ctypefunc, ctypeptr, ctypevoid + from pypy.module._cffi_backend import ctypeptr, ctypearray space = self.space # - ok = False - if isinstance(w_ctype, ctypefunc.W_CTypeFunc): - ok = True - if (isinstance(w_ctype, ctypeptr.W_CTypePointer) and - isinstance(w_ctype.ctitem, ctypevoid.W_CTypeVoid)): - ok = True - if not ok: + if not isinstance(w_ctype, ctypeptr.W_CTypePtrOrArray): raise oefmt(space.w_TypeError, - "function cdata expected, got '%s'", w_ctype.name) + "function or pointer or array cdata expected, got '%s'", + w_ctype.name) # try: cdata = dlsym(self.handle, name) except KeyError: - raise oefmt(space.w_KeyError, - "function '%s' not found in library '%s'", + raise oefmt(space.w_AttributeError, + "function/symbol '%s' not found in library '%s'", name, self.name) + if isinstance(w_ctype, ctypearray.W_CTypeArray) and w_ctype.length < 0: + w_ctype = w_ctype.ctptr return W_CData(space, rffi.cast(rffi.CCHARP, cdata), w_ctype) @unwrap_spec(w_ctype=W_CType, name=str) 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 @@ -365,7 +365,7 @@ x = find_and_load_library(None) BVoidP = new_pointer_type(new_void_type()) assert x.load_function(BVoidP, 'strcpy') - py.test.raises(KeyError, x.load_function, + py.test.raises(AttributeError, x.load_function, BVoidP, 'xxx_this_function_does_not_exist') # the next one is from 'libm', not 'libc', but we assume # that it is already loaded too, so it should work diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -670,14 +670,13 @@ self.space = space self.saved_w = [] self.w_iterable = space.iter(w_iterable) - self.index = 0 - self.exhausted = False + self.index = 0 # 0 during the first iteration; > 0 afterwards def iter_w(self): return self.space.wrap(self) def next_w(self): - if self.exhausted: + if self.index > 0: if not self.saved_w: raise OperationError(self.space.w_StopIteration, self.space.w_None) try: @@ -692,26 +691,27 @@ w_obj = self.space.next(self.w_iterable) except OperationError as e: if e.match(self.space, self.space.w_StopIteration): - self.exhausted = True + self.index = 1 if not self.saved_w: raise - self.index = 1 w_obj = self.saved_w[0] else: raise else: - self.index += 1 self.saved_w.append(w_obj) return w_obj def descr_reduce(self, space): + # reduces differently than CPython 3.5. Unsure if it is a + # problem. To be on the safe side, keep three arguments for + # __setstate__; CPython takes two. return space.newtuple([ space.type(self), space.newtuple([self.w_iterable]), space.newtuple([ space.newlist(self.saved_w), space.wrap(self.index), - space.wrap(self.exhausted), + space.wrap(self.index > 0), ]), ]) @@ -719,7 +719,7 @@ w_saved, w_index, w_exhausted = space.unpackiterable(w_state, 3) self.saved_w = space.unpackiterable(w_saved) self.index = space.int_w(w_index) - self.exhausted = space.bool_w(w_exhausted) + # w_exhausted ignored def W_Cycle___new__(space, w_subtype, w_iterable): diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py @@ -1227,6 +1227,26 @@ assert list(a)[:1000] + [0] * (len(a)-1000) == list(b) f.close() + def test_ffi_buffer_comparisons(self): + ffi = FFI(backend=self.Backend()) + ba = bytearray(range(100, 110)) + assert ba == memoryview(ba) # justification for the following + a = ffi.new("uint8_t[]", list(ba)) + c = ffi.new("uint8_t[]", [99] + list(ba)) + try: + b_full = ffi.buffer(a) + b_short = ffi.buffer(a, 3) + b_mid = ffi.buffer(a, 6) + b_other = ffi.buffer(c, 6) + except NotImplementedError as e: + py.test.skip(str(e)) + else: + content = b_full[:] + assert content == b_full == ba + assert b_other < b_short < b_mid < b_full + assert ba > b_mid > ba[0:2] + assert b_short != ba[1:4] + def test_array_in_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo_s { int len; short data[5]; };") diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py @@ -193,9 +193,12 @@ setattr(s, name, value) assert getattr(s, name) == value raw1 = ffi.buffer(s)[:] + buff1 = ffi.buffer(s) t = lib.try_with_value(fnames.index(name), value) raw2 = ffi.buffer(t, len(raw1))[:] assert raw1 == raw2 + buff2 = ffi.buffer(t, len(buff1)) + assert buff1 == buff2 def test_bitfield_basic(self): self.check("int a; int b:9; int c:20; int y;", 8, 4, 12) diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ownlib.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ownlib.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ownlib.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ownlib.py @@ -283,3 +283,21 @@ assert ret.right == ownlib.right assert ret.top == ownlib.top assert ret.bottom == ownlib.bottom + + def test_addressof_lib(self): + if self.module is None: + py.test.skip("fix the auto-generation of the tiny test lib") + if self.Backend is CTypesBackend: + py.test.skip("not implemented with the ctypes backend") + ffi = FFI(backend=self.Backend()) + ffi.cdef("long left; int test_getting_errno(void);") + lib = ffi.dlopen(self.module) + lib.left = 123456 + p = ffi.addressof(lib, "left") + assert ffi.typeof(p) == ffi.typeof("long *") + assert p[0] == 123456 + p[0] += 1 + assert lib.left == 123457 + pfn = ffi.addressof(lib, "test_getting_errno") + assert ffi.typeof(pfn) == ffi.typeof("int(*)(void)") + assert pfn == lib.test_getting_errno diff --git a/rpython/translator/c/src/stacklet/stacklet.c b/rpython/translator/c/src/stacklet/stacklet.c --- a/rpython/translator/c/src/stacklet/stacklet.c +++ b/rpython/translator/c/src/stacklet/stacklet.c @@ -5,8 +5,8 @@ #include "src/stacklet/stacklet.h" #include <stddef.h> -#include <assert.h> #include <string.h> +#include <stdio.h> /************************************************************ * platform specific code @@ -34,7 +34,7 @@ /************************************************************/ struct stacklet_s { - /* The portion of the real stack claimed by this paused tealet. */ + /* The portion of the real stack claimed by this paused stacklet. */ char *stack_start; /* the "near" end of the stack */ char *stack_stop; /* the "far" end of the stack */ @@ -69,6 +69,19 @@ struct stacklet_s *g_target; }; +#define _check(x) do { if (!(x)) _check_failed(#x); } while (0) + +static void _check_failed(const char *check) +{ + fprintf(stderr, "FATAL: stacklet: %s failed\n", check); + abort(); +} + +static void check_valid(struct stacklet_s *g) +{ + _check(g->stack_saved >= 0); +} + /***************************************************************/ static void g_save(struct stacklet_s* g, char* stop @@ -96,7 +109,8 @@ */ ptrdiff_t sz1 = g->stack_saved; ptrdiff_t sz2 = stop - g->stack_start; - assert(stop <= g->stack_stop); + check_valid(g); + _check(stop <= g->stack_stop); if (sz2 > sz1) { char *c = (char *)(g + 1); @@ -146,11 +160,13 @@ { struct stacklet_s *current = thrd->g_stack_chain_head; char *target_stop = g_target->stack_stop; + check_valid(g_target); - /* save and unlink tealets that are completely within + /* save and unlink stacklets that are completely within the area to clear. */ while (current != NULL && current->stack_stop <= target_stop) { struct stacklet_s *prev = current->stack_prev; + check_valid(current); current->stack_prev = NULL; if (current != g_target) { /* don't bother saving away g_target, because @@ -222,14 +238,16 @@ struct stacklet_thread_s *thrd = (struct stacklet_thread_s *)rawthrd; struct stacklet_s *g = thrd->g_target; ptrdiff_t stack_saved = g->stack_saved; + check_valid(g); - assert(new_stack_pointer == g->stack_start); + _check(new_stack_pointer == g->stack_start); #if STACK_DIRECTION == 0 memcpy(g->stack_start, g+1, stack_saved); #else memcpy(g->stack_start - stack_saved, g+1, stack_saved); #endif thrd->g_current_stack_stop = g->stack_stop; + g->stack_saved = -13; /* debugging */ free(g); return EMPTY_STACKLET_HANDLE; } @@ -250,10 +268,11 @@ result = run(thrd->g_source, run_arg); /* Then switch to 'result'. */ + check_valid(result); thrd->g_target = result; _stacklet_switchstack(g_destroy_state, g_restore_state, thrd); - assert(!"stacklet: we should not return here"); + _check_failed("we should not return here"); abort(); } /* The second time it returns. */ @@ -287,7 +306,7 @@ stacklet_run_fn run, void *run_arg) { long stackmarker; - assert((char *)NULL < (char *)&stackmarker); + _check((char *)NULL < (char *)&stackmarker); if (thrd->g_current_stack_stop <= (char *)&stackmarker) thrd->g_current_stack_stop = ((char *)&stackmarker) + 1; @@ -300,6 +319,7 @@ { long stackmarker; stacklet_thread_handle thrd = target->stack_thrd; + check_valid(target); if (thrd->g_current_stack_stop <= (char *)&stackmarker) thrd->g_current_stack_stop = ((char *)&stackmarker) + 1; @@ -310,6 +330,7 @@ void stacklet_destroy(stacklet_handle target) { + check_valid(target); if (target->stack_prev != NULL) { /* 'target' appears to be in the chained list 'unsaved_stack', so remove it from there. Note that if 'thrd' was already @@ -319,12 +340,15 @@ we don't even read 'stack_thrd', already deallocated. */ stacklet_thread_handle thrd = target->stack_thrd; struct stacklet_s **pp = &thrd->g_stack_chain_head; - for (; *pp != NULL; pp = &(*pp)->stack_prev) + for (; *pp != NULL; pp = &(*pp)->stack_prev) { + check_valid(*pp); if (*pp == target) { *pp = target->stack_prev; break; } + } } + target->stack_saved = -11; /* debugging */ free(target); } @@ -334,6 +358,7 @@ long delta; if (context == NULL) return ptr; + check_valid(context); delta = p - context->stack_start; if (((unsigned long)delta) < ((unsigned long)context->stack_saved)) { /* a pointer to a saved away word */ @@ -345,8 +370,8 @@ /* out-of-stack pointer! it's only ok if we are the main stacklet and we are reading past the end, because the main stacklet's stack stop is not exactly known. */ - assert(delta >= 0); - assert(((long)context->stack_stop) & 1); + _check(delta >= 0); + _check(((long)context->stack_stop) & 1); } return ptr; } _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit