Author: mattip <matti.pi...@gmail.com> Branch: release-2.6.x Changeset: r77576:fcdb94156515 Date: 2015-05-26 15:32 +0300 http://bitbucket.org/pypy/pypy/changeset/fcdb94156515/
Log: merge default into release diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -38,8 +38,8 @@ Armin Rigo Maciej Fijalkowski Carl Friedrich Bolz + Amaury Forgeot d'Arc Antonio Cuni - Amaury Forgeot d'Arc Samuele Pedroni Alex Gaynor Brian Kearns @@ -50,9 +50,9 @@ Holger Krekel Christian Tismer Hakan Ardo - Benjamin Peterson Manuel Jacob Ronan Lamy + Benjamin Peterson Anders Chrigstrom Eric van Riet Paap Wim Lavrijsen @@ -63,8 +63,8 @@ Sven Hager Anders Lehmann Aurelien Campeas + Remi Meier Niklaus Haldimann - Remi Meier Camillo Bruni Laura Creighton Toon Verwaest @@ -76,10 +76,10 @@ David Edelsohn Anders Hammarquist Jakub Gustak + Gregor Wegberg Guido Wesdorp Lawrence Oluyede Bartosz Skowron - Gregor Wegberg Daniel Roberts Niko Matsakis Adrien Di Mascio @@ -87,10 +87,11 @@ Ludovic Aubry Jacob Hallen Jason Creighton + Richard Plangger Alex Martelli Michal Bendowski + stian Jan de Mooij - stian Tyler Wade Michael Foord Stephan Diehl @@ -133,15 +134,15 @@ Georg Brandl Bert Freudenberg Stian Andreassen + Edd Barrett Wanja Saatkamp Gerald Klix Mike Blume + Tobias Pape Oscar Nierstrasz Stefan H. Muller - Edd Barrett Jeremy Thurgood Rami Chowdhury - Tobias Pape Eugene Oden Henry Mason Vasily Kuznetsov @@ -167,11 +168,13 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu + Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb Karl Bartel Wouter van Heyst + Sebastian Pawluś Brian Dorsey Victor Stinner Andrews Medina @@ -188,6 +191,7 @@ Neil Shepperd Stanislaw Halik Mikael Schönenberg + Berkin Ilbeyi Elmo M?ntynen Jonathan David Riehl Anders Qvist @@ -211,11 +215,11 @@ Carl Meyer Karl Ramm Pieter Zieschang - Sebastian Pawluś Gabriel Lukas Vacek Andrew Dalke Sylvain Thenault + Jakub Stasiak Nathan Taylor Vladimir Kryachko Jacek Generowicz @@ -242,6 +246,7 @@ Tomo Cocoa Toni Mattis Lucas Stadler + Julian Berman roberto@goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -253,6 +258,8 @@ Ben Darnell Roberto De Ioris Juan Francisco Cantero Hurtado + Ruochen Huang + Jeong YunWon Godefroid Chappelle Joshua Gilbert Dan Colish @@ -271,6 +278,7 @@ Christian Muirhead Berker Peksag James Lan + Volodymyr Vladymyrov shoma hosaka Daniel Neuhäuser Ben Mather @@ -316,6 +324,7 @@ yasirs Michael Chermside Anna Ravencroft + Andrey Churin Dan Crosta Julien Phalip Roman Podoliaka 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.0.2 +Version: 1.0.3 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.0.2" -__version_info__ = (1, 0, 2) +__version__ = "1.0.3" +__version_info__ = (1, 0, 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__ 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.6 +Version: 0.4.7 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 @@ -1,7 +1,7 @@ import sys import _continuation -__version__ = "0.4.6" +__version__ = "0.4.7" # ____________________________________________________________ # Exceptions diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -39,7 +39,6 @@ ]) if sys.platform.startswith('linux') and sys.maxint > 2147483647: - if 0: # XXX disabled until we fix the absurd .so mess working_modules.add('_vmprof') translation_modules = default_modules.copy() diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst --- a/pypy/doc/contributor.rst +++ b/pypy/doc/contributor.rst @@ -8,8 +8,8 @@ Armin Rigo Maciej Fijalkowski Carl Friedrich Bolz + Amaury Forgeot d'Arc Antonio Cuni - Amaury Forgeot d'Arc Samuele Pedroni Alex Gaynor Brian Kearns @@ -20,9 +20,9 @@ Holger Krekel Christian Tismer Hakan Ardo - Benjamin Peterson Manuel Jacob Ronan Lamy + Benjamin Peterson Anders Chrigstrom Eric van Riet Paap Wim Lavrijsen @@ -33,8 +33,8 @@ Sven Hager Anders Lehmann Aurelien Campeas + Remi Meier Niklaus Haldimann - Remi Meier Camillo Bruni Laura Creighton Toon Verwaest @@ -46,10 +46,10 @@ David Edelsohn Anders Hammarquist Jakub Gustak + Gregor Wegberg Guido Wesdorp Lawrence Oluyede Bartosz Skowron - Gregor Wegberg Daniel Roberts Niko Matsakis Adrien Di Mascio @@ -57,10 +57,11 @@ Ludovic Aubry Jacob Hallen Jason Creighton + Richard Plangger Alex Martelli Michal Bendowski + stian Jan de Mooij - stian Tyler Wade Michael Foord Stephan Diehl @@ -103,15 +104,15 @@ Georg Brandl Bert Freudenberg Stian Andreassen + Edd Barrett Wanja Saatkamp Gerald Klix Mike Blume + Tobias Pape Oscar Nierstrasz Stefan H. Muller - Edd Barrett Jeremy Thurgood Rami Chowdhury - Tobias Pape Eugene Oden Henry Mason Vasily Kuznetsov @@ -137,11 +138,13 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu + Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb Karl Bartel Wouter van Heyst + Sebastian Pawluś Brian Dorsey Victor Stinner Andrews Medina @@ -158,6 +161,7 @@ Neil Shepperd Stanislaw Halik Mikael Schönenberg + Berkin Ilbeyi Elmo M?ntynen Jonathan David Riehl Anders Qvist @@ -181,11 +185,11 @@ Carl Meyer Karl Ramm Pieter Zieschang - Sebastian Pawluś Gabriel Lukas Vacek Andrew Dalke Sylvain Thenault + Jakub Stasiak Nathan Taylor Vladimir Kryachko Jacek Generowicz @@ -212,6 +216,7 @@ Tomo Cocoa Toni Mattis Lucas Stadler + Julian Berman roberto@goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -223,6 +228,8 @@ Ben Darnell Roberto De Ioris Juan Francisco Cantero Hurtado + Ruochen Huang + Jeong YunWon Godefroid Chappelle Joshua Gilbert Dan Colish @@ -241,6 +248,7 @@ Christian Muirhead Berker Peksag James Lan + Volodymyr Vladymyrov shoma hosaka Daniel Neuhäuser Ben Mather @@ -286,6 +294,7 @@ yasirs Michael Chermside Anna Ravencroft + Andrey Churin Dan Crosta Julien Phalip Roman Podoliaka diff --git a/pypy/doc/tool/makecontributor.py b/pypy/doc/tool/makecontributor.py --- a/pypy/doc/tool/makecontributor.py +++ b/pypy/doc/tool/makecontributor.py @@ -69,6 +69,7 @@ 'Rami Chowdhury': ['necaris'], 'Stanislaw Halik':['w31rd0'], 'Wenzhu Man':['wenzhu man', 'wenzhuman'], + 'Anton Gulenko':['anton gulenko'], } alias_map = {} 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 @@ -2,7 +2,7 @@ from pypy.interpreter.mixedmodule import MixedModule from rpython.rlib import rdynload -VERSION = "1.0.2" +VERSION = "1.0.3" class Module(MixedModule): 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 @@ -188,16 +188,7 @@ if self.value_fits_long: value = misc.as_long(self.space, w_ob) if self.value_smaller_than_long: - size = self.size - if size == 1: - signextended = misc.signext(value, 1) - elif size == 2: - signextended = misc.signext(value, 2) - elif size == 4: - signextended = misc.signext(value, 4) - else: - raise AssertionError("unsupported size") - if value != signextended: + if value != misc.signext(value, self.size): self._overflow(w_ob) misc.write_raw_signed_data(cdata, value, self.size) else: diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py --- a/pypy/module/_cffi_backend/ffi_obj.py +++ b/pypy/module/_cffi_backend/ffi_obj.py @@ -10,7 +10,7 @@ from pypy.module._cffi_backend import parse_c_type, realize_c_type from pypy.module._cffi_backend import newtype, cerrno, ccallback, ctypearray from pypy.module._cffi_backend import ctypestruct, ctypeptr, handle -from pypy.module._cffi_backend import cbuffer, func, cgc, structwrapper +from pypy.module._cffi_backend import cbuffer, func, cgc, wrapper from pypy.module._cffi_backend import cffi_opcode from pypy.module._cffi_backend.ctypeobj import W_CType from pypy.module._cffi_backend.cdataobj import W_CData @@ -478,7 +478,7 @@ corresponding <ctype> object. It can also be used on 'cdata' instance to get its C type.""" # - if isinstance(w_arg, structwrapper.W_StructWrapper): + if isinstance(w_arg, wrapper.W_FunctionWrapper): return w_arg.typeof(self) return self.ffi_type(w_arg, ACCEPT_STRING | ACCEPT_CDATA) diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py --- a/pypy/module/_cffi_backend/lib_obj.py +++ b/pypy/module/_cffi_backend/lib_obj.py @@ -12,7 +12,7 @@ from pypy.module._cffi_backend.realize_c_type import getop, getarg from pypy.module._cffi_backend.cdataobj import W_CData from pypy.module._cffi_backend.ctypefunc import W_CTypeFunc -from pypy.module._cffi_backend.structwrapper import W_StructWrapper +from pypy.module._cffi_backend.wrapper import W_FunctionWrapper class W_LibObject(W_Root): @@ -49,7 +49,7 @@ num += 1 self.ffi.included_ffis_libs = includes[:] - def _build_cpython_func(self, g): + def _build_cpython_func(self, g, fnname): # Build a function: in the PyPy version, these are all equivalent # and 'g->address' is a pointer to a function of exactly the # C type specified --- almost: arguments that are structs or @@ -64,10 +64,8 @@ # ptr = rffi.cast(rffi.CCHARP, g.c_address) assert ptr - w_cdata = W_CData(self.space, ptr, w_ct) - if locs is not None: - w_cdata = W_StructWrapper(w_cdata, locs, rawfunctype) - return w_cdata + return W_FunctionWrapper(self.space, ptr, w_ct, + locs, rawfunctype, fnname) @jit.elidable_promote() def _get_attr_elidable(self, attr): @@ -100,7 +98,7 @@ op == cffi_opcode.OP_CPYTHON_BLTN_N or op == cffi_opcode.OP_CPYTHON_BLTN_O): # A function - w_result = self._build_cpython_func(g) + w_result = self._build_cpython_func(g, attr) # elif op == cffi_opcode.OP_GLOBAL_VAR: # A global variable of the exact type specified here @@ -210,7 +208,7 @@ # if ((isinstance(w_value, W_CData) and isinstance(w_value.ctype, W_CTypeFunc)) - or isinstance(w_value, W_StructWrapper)): + or isinstance(w_value, W_FunctionWrapper)): # '&func' is 'func' in C, for a constant function 'func' return w_value # diff --git a/pypy/module/_cffi_backend/misc.py b/pypy/module/_cffi_backend/misc.py --- a/pypy/module/_cffi_backend/misc.py +++ b/pypy/module/_cffi_backend/misc.py @@ -216,10 +216,9 @@ neg_msg = "can't convert negative number to unsigned" ovf_msg = "long too big to convert" -@specialize.arg(1) def signext(value, size): # 'value' is sign-extended from 'size' bytes to a full integer. - # 'size' should be a constant smaller than a full integer size. + # 'size' should be smaller than a full integer size. if size == rffi.sizeof(rffi.SIGNEDCHAR): return rffi.cast(lltype.Signed, rffi.cast(rffi.SIGNEDCHAR, value)) elif size == rffi.sizeof(rffi.SHORT): 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 @@ -3335,4 +3335,4 @@ def test_version(): # this test is here mostly for PyPy - assert __version__ == "1.0.2" + assert __version__ == "1.0.3" 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 @@ -740,3 +740,45 @@ raises(AttributeError, ffi.addressof, lib, 'unknown_var') raises(AttributeError, ffi.addressof, lib, "FOOBAR") assert ffi.addressof(lib, 'FetchRectBottom') == lib.FetchRectBottom + + def test_defines__CFFI_(self): + # Check that we define the macro _CFFI_ automatically. + # It should be done before including Python.h, so that PyPy's Python.h + # can check for it. + ffi, lib = self.prepare(""" + #define CORRECT 1 + """, "test_defines__CFFI_", """ + #ifdef _CFFI_ + # define CORRECT 1 + #endif + """) + assert lib.CORRECT == 1 + + def test_unpack_args(self): + ffi, lib = self.prepare( + "void foo0(void); void foo1(int); void foo2(int, int);", + "test_unpack_args", """ + void foo0(void) { } + void foo1(int x) { } + void foo2(int x, int y) { } + """) + assert 'foo0' in repr(lib.foo0) + assert 'foo1' in repr(lib.foo1) + assert 'foo2' in repr(lib.foo2) + lib.foo0() + lib.foo1(42) + lib.foo2(43, 44) + e1 = raises(TypeError, lib.foo0, 42) + e2 = raises(TypeError, lib.foo0, 43, 44) + e3 = raises(TypeError, lib.foo1) + e4 = raises(TypeError, lib.foo1, 43, 44) + e5 = raises(TypeError, lib.foo2) + e6 = raises(TypeError, lib.foo2, 42) + e7 = raises(TypeError, lib.foo2, 45, 46, 47) + assert str(e1.value) == "foo0() takes no arguments (1 given)" + assert str(e2.value) == "foo0() takes no arguments (2 given)" + assert str(e3.value) == "foo1() takes exactly one argument (0 given)" + assert str(e4.value) == "foo1() takes exactly one argument (2 given)" + assert str(e5.value) == "foo2() takes exactly 2 arguments (0 given)" + assert str(e6.value) == "foo2() takes exactly 2 arguments (1 given)" + assert str(e7.value) == "foo2() takes exactly 2 arguments (3 given)" diff --git a/pypy/module/_cffi_backend/structwrapper.py b/pypy/module/_cffi_backend/wrapper.py rename from pypy/module/_cffi_backend/structwrapper.py rename to pypy/module/_cffi_backend/wrapper.py --- a/pypy/module/_cffi_backend/structwrapper.py +++ b/pypy/module/_cffi_backend/wrapper.py @@ -1,3 +1,4 @@ +from pypy.interpreter.error import oefmt from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app @@ -10,7 +11,7 @@ from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion -class W_StructWrapper(W_Root): +class W_FunctionWrapper(W_Root): """A wrapper around a real W_CData which points to a function generated in the C code. The real W_CData has got no struct/union argument (only pointers to it), and no struct/union return type @@ -21,17 +22,19 @@ """ _immutable_ = True - def __init__(self, w_cdata, locs, rawfunctype): - space = w_cdata.space - ctype = w_cdata.ctype + def __init__(self, space, fnptr, ctype, locs, rawfunctype, fnname): assert isinstance(ctype, W_CTypeFunc) - assert len(ctype.fargs) == len(locs) + assert ctype.cif_descr is not None # not for '...' functions + assert locs is None or len(ctype.fargs) == len(locs) # self.space = space - self.w_cdata = w_cdata + self.fnptr = fnptr + self.ctype = ctype self.locs = locs - self.fargs = ctype.fargs self.rawfunctype = rawfunctype + self.fnname = fnname + self.nargs_expected = len(ctype.fargs) - (locs is not None and + locs[0] == 'R') def typeof(self, ffi): return self.rawfunctype.unwrap_as_fnptr(ffi) @@ -41,12 +44,12 @@ # replaces struct/union arguments with ptr-to-struct/union arguments space = self.space locs = self.locs - result_w = args_w[:] - for i in range(start_index, min(len(args_w), len(locs))): + fargs = self.ctype.fargs + for i in range(start_index, len(locs)): if locs[i] != 'A': continue w_arg = args_w[i] - farg = self.fargs[i] # <ptr to struct/union> + farg = fargs[i] # <ptr to struct/union> assert isinstance(farg, W_CTypePtrOrArray) if isinstance(w_arg, W_CData) and w_arg.ctype is farg.ctitem: # fast way: we are given a W_CData "struct", so just make @@ -62,25 +65,49 @@ if space.is_w(w_arg, space.w_None): continue w_arg = farg.newp(w_arg) - result_w[i] = w_arg - return result_w + args_w[i] = w_arg def descr_call(self, args_w): - # If the result we want to present to the user is "returns struct", - # then internally allocate the struct and pass a pointer to it as - # a first argument. - if self.locs[0] == 'R': - w_result_cdata = self.fargs[0].newp(self.space.w_None) - args_w = [w_result_cdata] + args_w - self.w_cdata.call(self._prepare(args_w, 1)) - assert isinstance(w_result_cdata, W_CDataPtrToStructOrUnion) - return w_result_cdata.structobj - else: - return self.w_cdata.call(self._prepare(args_w, 0)) + if len(args_w) != self.nargs_expected: + space = self.space + if self.nargs_expected == 0: + raise oefmt(space.w_TypeError, + "%s() takes no arguments (%d given)", + self.fnname, len(args_w)) + elif self.nargs_expected == 1: + raise oefmt(space.w_TypeError, + "%s() takes exactly one argument (%d given)", + self.fnname, len(args_w)) + else: + raise oefmt(space.w_TypeError, + "%s() takes exactly %d arguments (%d given)", + self.fnname, self.nargs_expected, len(args_w)) + # + if self.locs is not None: + # This case is if there are structs as arguments or return values. + # If the result we want to present to the user is "returns struct", + # then internally allocate the struct and pass a pointer to it as + # a first argument. + if self.locs[0] == 'R': + w_result_cdata = self.ctype.fargs[0].newp(self.space.w_None) + args_w = [w_result_cdata] + args_w + self._prepare(args_w, 1) + self.ctype._call(self.fnptr, args_w) # returns w_None + assert isinstance(w_result_cdata, W_CDataPtrToStructOrUnion) + return w_result_cdata.structobj + else: + args_w = args_w[:] + self._prepare(args_w, 0) + # + return self.ctype._call(self.fnptr, args_w) + def descr_repr(self, space): + return space.wrap("<FFIFunctionWrapper for %s()>" % (self.fnname,)) -W_StructWrapper.typedef = TypeDef( - 'FFIFuncStructWrapper', - __call__ = interp2app(W_StructWrapper.descr_call), + +W_FunctionWrapper.typedef = TypeDef( + 'FFIFunctionWrapper', + __repr__ = interp2app(W_FunctionWrapper.descr_repr), + __call__ = interp2app(W_FunctionWrapper.descr_call), ) -W_StructWrapper.typedef.acceptable_as_base_class = False +W_FunctionWrapper.typedef.acceptable_as_base_class = False diff --git a/pypy/module/_vmprof/interp_vmprof.py b/pypy/module/_vmprof/interp_vmprof.py --- a/pypy/module/_vmprof/interp_vmprof.py +++ b/pypy/module/_vmprof/interp_vmprof.py @@ -27,15 +27,15 @@ include_dirs = [SRC], includes = ['vmprof.h', 'trampoline.h'], separate_module_files = [SRC.join('trampoline.asmgcc.s')], - libraries = ['unwind'], + libraries = ['dl'], post_include_bits=[""" - void pypy_vmprof_init(void); + int pypy_vmprof_init(void); """], separate_module_sources=[""" - void pypy_vmprof_init(void) { - vmprof_set_mainloop(pypy_execute_frame_trampoline, 0, + int pypy_vmprof_init(void) { + return vmprof_set_mainloop(pypy_execute_frame_trampoline, 0, NULL); } """], @@ -63,7 +63,7 @@ _nowrapper=True, sandboxsafe=True, random_effects_on_gcobjs=True) -pypy_vmprof_init = rffi.llexternal("pypy_vmprof_init", [], lltype.Void, +pypy_vmprof_init = rffi.llexternal("pypy_vmprof_init", [], rffi.INT, compilation_info=eci) vmprof_enable = rffi.llexternal("vmprof_enable", [rffi.INT, rffi.LONG, rffi.INT, @@ -73,6 +73,9 @@ vmprof_disable = rffi.llexternal("vmprof_disable", [], rffi.INT, compilation_info=eci, save_err=rffi.RFFI_SAVE_ERRNO) +vmprof_get_error = rffi.llexternal("vmprof_get_error", [], rffi.CCHARP, + compilation_info=eci, + save_err=rffi.RFFI_SAVE_ERRNO) vmprof_register_virtual_function = rffi.llexternal( "vmprof_register_virtual_function", @@ -142,7 +145,11 @@ self.write_header(fileno, period_usec) if not self.ever_enabled: if we_are_translated(): - pypy_vmprof_init() + res = pypy_vmprof_init() + if res: + raise OperationError( + space.w_IOError, + space.wrap(rffi.charp2str(vmprof_get_error()))) self.ever_enabled = True self.gather_all_code_objs(space) space.register_code_callback(vmprof_register_code) diff --git a/pypy/module/_vmprof/src/vmprof.c b/pypy/module/_vmprof/src/vmprof.c --- a/pypy/module/_vmprof/src/vmprof.c +++ b/pypy/module/_vmprof/src/vmprof.c @@ -27,9 +27,10 @@ #include <sys/types.h> #include <errno.h> #include <pthread.h> +#include <dlfcn.h> -#define UNW_LOCAL_ONLY -#include <libunwind.h> +//#define UNW_LOCAL_ONLY +//#include <libunwind.h> #include "vmprof.h" @@ -44,6 +45,7 @@ static char profile_write_buffer[BUFFER_SIZE]; static int profile_buffer_position = 0; void* vmprof_mainloop_func; +char* vmprof_error = NULL; static ptrdiff_t mainloop_sp_offset; static vmprof_get_virtual_ip_t mainloop_get_virtual_ip; static long last_period_usec = 0; @@ -59,6 +61,11 @@ #define MARKER_VIRTUAL_IP '\x02' #define MARKER_TRAILER '\x03' +int (*unw_get_reg)(unw_cursor_t*, int, unw_word_t*) = NULL; +int (*unw_step)(unw_cursor_t*) = NULL; +int (*unw_init_local)(unw_cursor_t *, unw_context_t *) = NULL; +int (*unw_get_proc_info)(unw_cursor_t *, unw_proc_info_t *) = NULL; + static void prof_word(long x) { ((long*)(profile_write_buffer + profile_buffer_position))[0] = x; profile_buffer_position += sizeof(long); @@ -342,11 +349,44 @@ * ************************************************************* */ -void vmprof_set_mainloop(void* func, ptrdiff_t sp_offset, +int vmprof_set_mainloop(void* func, ptrdiff_t sp_offset, vmprof_get_virtual_ip_t get_virtual_ip) { + void *libhandle; + mainloop_sp_offset = sp_offset; mainloop_get_virtual_ip = get_virtual_ip; vmprof_mainloop_func = func; + if (!unw_get_reg) { + if (!(libhandle = dlopen("libunwind.so", RTLD_LAZY | RTLD_LOCAL))) { + vmprof_error = dlerror(); + return -1; + } + if (!(unw_get_reg = dlsym(libhandle, "_ULx86_64_get_reg"))) { + vmprof_error = dlerror(); + return -1; + } + if (!(unw_get_proc_info = dlsym(libhandle, "_ULx86_64_get_proc_info"))){ + vmprof_error = dlerror(); + return -1; + } + if (!(unw_init_local = dlsym(libhandle, "_ULx86_64_init_local"))) { + vmprof_error = dlerror(); + return -1; + } + if (!(unw_step = dlsym(libhandle, "_ULx86_64_step"))) { + vmprof_error = dlerror(); + return -1; + } + } + return 0; +} + +char* vmprof_get_error() +{ + char* res; + res = vmprof_error; + vmprof_error = NULL; + return res; } int vmprof_enable(int fd, long period_usec, int write_header, char *s, diff --git a/pypy/module/_vmprof/src/vmprof.h b/pypy/module/_vmprof/src/vmprof.h --- a/pypy/module/_vmprof/src/vmprof.h +++ b/pypy/module/_vmprof/src/vmprof.h @@ -2,11 +2,110 @@ #define VMPROF_VMPROF_H_ #include <stddef.h> +#include <stdint.h> +#include <ucontext.h> + +// copied from libunwind.h + +typedef enum + { + UNW_X86_64_RAX, + UNW_X86_64_RDX, + UNW_X86_64_RCX, + UNW_X86_64_RBX, + UNW_X86_64_RSI, + UNW_X86_64_RDI, + UNW_X86_64_RBP, + UNW_X86_64_RSP, + UNW_X86_64_R8, + UNW_X86_64_R9, + UNW_X86_64_R10, + UNW_X86_64_R11, + UNW_X86_64_R12, + UNW_X86_64_R13, + UNW_X86_64_R14, + UNW_X86_64_R15, + UNW_X86_64_RIP, +#ifdef CONFIG_MSABI_SUPPORT + UNW_X86_64_XMM0, + UNW_X86_64_XMM1, + UNW_X86_64_XMM2, + UNW_X86_64_XMM3, + UNW_X86_64_XMM4, + UNW_X86_64_XMM5, + UNW_X86_64_XMM6, + UNW_X86_64_XMM7, + UNW_X86_64_XMM8, + UNW_X86_64_XMM9, + UNW_X86_64_XMM10, + UNW_X86_64_XMM11, + UNW_X86_64_XMM12, + UNW_X86_64_XMM13, + UNW_X86_64_XMM14, + UNW_X86_64_XMM15, + UNW_TDEP_LAST_REG = UNW_X86_64_XMM15, +#else + UNW_TDEP_LAST_REG = UNW_X86_64_RIP, +#endif + + /* XXX Add other regs here */ + + /* frame info (read-only) */ + UNW_X86_64_CFA, + + UNW_TDEP_IP = UNW_X86_64_RIP, + UNW_TDEP_SP = UNW_X86_64_RSP, + UNW_TDEP_BP = UNW_X86_64_RBP, + UNW_TDEP_EH = UNW_X86_64_RAX + } +x86_64_regnum_t; + +typedef uint64_t unw_word_t; + +#define UNW_TDEP_CURSOR_LEN 127 + +typedef struct unw_cursor + { + unw_word_t opaque[UNW_TDEP_CURSOR_LEN]; + } +unw_cursor_t; + +#define UNW_REG_IP UNW_X86_64_RIP +#define UNW_REG_SP UNW_X86_64_RSP + +typedef ucontext_t unw_context_t; + +typedef struct unw_proc_info + { + unw_word_t start_ip; /* first IP covered by this procedure */ + unw_word_t end_ip; /* first IP NOT covered by this procedure */ + unw_word_t lsda; /* address of lang.-spec. data area (if any) */ + unw_word_t handler; /* optional personality routine */ + unw_word_t gp; /* global-pointer value for this procedure */ + unw_word_t flags; /* misc. flags */ + + int format; /* unwind-info format (arch-specific) */ + int unwind_info_size; /* size of the information (if applicable) */ + void *unwind_info; /* unwind-info (arch-specific) */ + } +unw_proc_info_t; + +// functions copied from libunwind using dlopen + +extern int (*unw_get_reg)(unw_cursor_t*, int, unw_word_t*); +extern int (*unw_step)(unw_cursor_t*); +extern int (*unw_init_local)(unw_cursor_t *, unw_context_t *); +extern int (*unw_get_proc_info)(unw_cursor_t *, unw_proc_info_t *); + +// end of copy + +extern char* vmprof_error; typedef void* (*vmprof_get_virtual_ip_t)(void*); +char* vmprof_get_error(); extern void* vmprof_mainloop_func; -void vmprof_set_mainloop(void* func, ptrdiff_t sp_offset, +int vmprof_set_mainloop(void* func, ptrdiff_t sp_offset, vmprof_get_virtual_ip_t get_virtual_ip); void vmprof_register_virtual_function(const char* name, void* start, void* end); diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py @@ -208,6 +208,9 @@ """, ignore_ops=['guard_not_invalidated']) def test__cffi_call_c_int(self): + if sys.platform == 'win32': + py.test.skip("not tested on Windows (this test must pass on " + "other platforms, and it should work the same way)") def main(): import os try: @@ -248,6 +251,9 @@ """ % extra, ignore_ops=['guard_not_invalidated']) def test__cffi_call_size_t(self): + if sys.platform == 'win32': + py.test.skip("not tested on Windows (this test must pass on " + "other platforms, and it should work the same way)") def main(): import os try: diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py @@ -26,8 +26,11 @@ tmpdir.ensure(dir=1) c_file = tmpdir.join('_test_re_python.c') c_file.write(SRC) - ext = ffiplatform.get_extension(str(c_file), '_test_re_python', - export_symbols=['add42', 'globalvar42']) + ext = ffiplatform.get_extension( + str(c_file), + '_test_re_python', + export_symbols=['add42', 'add43', 'globalvar42'] + ) outputfilename = ffiplatform.compile(str(tmpdir), ext) mod.extmod = outputfilename mod.tmpdir = tmpdir diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py @@ -1,5 +1,5 @@ # Generated by pypy/tool/import_cffi.py -import sys, math, py +import os, sys, math, py from cffi import FFI, VerificationError, VerificationMissing, model from cffi import recompiler from pypy.module.test_lib_pypy.cffi_tests.support import * diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py --- a/pypy/tool/release/package.py +++ b/pypy/tool/release/package.py @@ -78,8 +78,9 @@ subprocess.check_call(args, cwd=cwd) except subprocess.CalledProcessError: print >>sys.stderr, """!!!!!!!!!!\nBuilding {0} bindings failed. -You can either install development headers package or -add --without-{0} option to skip packaging this binary CFFI extension.""".format(key) +You can either install development headers package, +add the --without-{0} option to skip packaging this +binary CFFI extension, or say --without-cffi.""".format(key) raise MissingDependenciesError(module) def pypy_runs(pypy_c, quiet=False): @@ -88,7 +89,7 @@ kwds['stderr'] = subprocess.PIPE return subprocess.call([str(pypy_c), '-c', 'pass'], **kwds) == 0 -def create_package(basedir, options): +def create_package(basedir, options, _fake=False): retval = 0 name = options.name if not name: @@ -104,13 +105,13 @@ pypy_c = basedir.join('pypy', 'goal', basename) else: pypy_c = py.path.local(override_pypy_c) - if not pypy_c.check(): + if not _fake and not pypy_c.check(): raise PyPyCNotFound( 'Expected but did not find %s.' ' Please compile pypy first, using translate.py,' ' or check that you gave the correct path' ' with --override_pypy_c' % pypy_c) - if not pypy_runs(pypy_c): + if not _fake and not pypy_runs(pypy_c): raise OSError("Running %r failed!" % (str(pypy_c),)) if not options.no_cffi: try: @@ -121,18 +122,17 @@ if sys.platform == 'win32' and not rename_pypy_c.lower().endswith('.exe'): rename_pypy_c += '.exe' binaries = [(pypy_c, rename_pypy_c)] - libpypy_name = 'libpypy-c.so' if not sys.platform.startswith('darwin') else 'libpypy-c.dylib' - libpypy_c = pypy_c.new(basename=libpypy_name) - if libpypy_c.check(): - # check that this libpypy_c is really needed - os.rename(str(libpypy_c), str(libpypy_c) + '~') - try: - if pypy_runs(pypy_c, quiet=True): - raise Exception("It seems that %r runs without needing %r. " - "Please check and remove the latter" % - (str(pypy_c), str(libpypy_c))) - finally: - os.rename(str(libpypy_c) + '~', str(libpypy_c)) + + if (sys.platform != 'win32' and # handled below + not _fake and os.path.getsize(str(pypy_c)) < 500000): + # This pypy-c is very small, so it means it relies on libpypy_c.so. + # If it would be bigger, it wouldn't. That's a hack. + libpypy_name = ('libpypy-c.so' if not sys.platform.startswith('darwin') + else 'libpypy-c.dylib') + libpypy_c = pypy_c.new(basename=libpypy_name) + if not libpypy_c.check(): + raise PyPyCNotFound('Expected pypy to be mostly in %r, but did ' + 'not find it' % (str(libpypy_c),)) binaries.append((libpypy_c, libpypy_name)) # builddir = options.builddir @@ -192,7 +192,9 @@ directory next to the dlls, as per build instructions.""" import traceback;traceback.print_exc() raise MissingDependenciesError('Tk runtime') - + + print '* Binaries:', [source.relto(str(basedir)) + for source, target in binaries] # Careful: to copy lib_pypy, copying just the hg-tracked files # would not be enough: there are also ctypes_config_cache/_*_cache.py. @@ -225,7 +227,11 @@ bindir.ensure(dir=True) for source, target in binaries: archive = bindir.join(target) - shutil.copy(str(source), str(archive)) + if not _fake: + shutil.copy(str(source), str(archive)) + else: + open(str(archive), 'wb').close() + os.chmod(str(archive), 0755) fix_permissions(pypydir) old_dir = os.getcwd() @@ -274,7 +280,7 @@ print "Ready in %s" % (builddir,) return retval, builddir # for tests -def package(*args): +def package(*args, **kwds): try: import argparse except ImportError: @@ -335,7 +341,7 @@ from rpython.tool.udir import udir options.builddir = udir.ensure("build", dir=True) assert '/' not in options.pypy_c - return create_package(basedir, options) + return create_package(basedir, options, **kwds) if __name__ == '__main__': diff --git a/pypy/tool/release/test/test_package.py b/pypy/tool/release/test/test_package.py --- a/pypy/tool/release/test/test_package.py +++ b/pypy/tool/release/test/test_package.py @@ -16,25 +16,10 @@ rename_pypy_c = 'pypy' exe_name_in_archive = 'bin/pypy' pypy_c = py.path.local(pypydir).join('goal', basename) - if not pypy_c.check(): - if sys.platform == 'win32': - import os, shutil - for d in os.environ['PATH'].split(';'): - if os.path.exists(os.path.join(d, 'cmd.exe')): - shutil.copy(os.path.join(d, 'cmd.exe'), str(pypy_c)) - break - else: - assert False, 'could not find cmd.exe' - else: - pypy_c.write("#!/bin/sh") - pypy_c.chmod(0755) - fake_pypy_c = True - else: - fake_pypy_c = False try: retval, builddir = package.package( '--without-cffi', str(py.path.local(pypydir).dirpath()), - test, rename_pypy_c) + test, rename_pypy_c, _fake=True) assert retval == 0 prefix = builddir.join(test) cpyver = '%d.%d' % CPYTHON_VERSION[:2] @@ -79,8 +64,7 @@ check_include('pypy_decl.h') check_include('numpy/arrayobject.h') finally: - if fake_pypy_c: - pypy_c.remove() + pass # to keep the indentation def test_with_zipfile_module(): prev = package.USE_ZIPFILE_MODULE diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py --- a/rpython/jit/backend/llsupport/assembler.py +++ b/rpython/jit/backend/llsupport/assembler.py @@ -6,7 +6,7 @@ ConstInt, BoxInt, AbstractFailDescr) from rpython.jit.metainterp.resoperation import ResOperation, rop from rpython.rlib import rgc -from rpython.rlib.debug import (debug_start, debug_stop, have_debug_prints, +from rpython.rlib.debug import (debug_start, debug_stop, have_debug_prints_for, debug_print) from rpython.rlib.rarithmetic import r_uint from rpython.rlib.objectmodel import specialize, compute_unique_id @@ -120,9 +120,7 @@ # if self._debug is already set it means that someone called # set_debug by hand before initializing the assembler. Leave it # as it is - debug_start('jit-backend-counts') - self.set_debug(have_debug_prints()) - debug_stop('jit-backend-counts') + self.set_debug(have_debug_prints_for('jit-backend-counts')) # when finishing, we only have one value at [0], the rest dies self.gcmap_for_finish = lltype.malloc(jitframe.GCMAP, 1, flavor='raw', diff --git a/rpython/jit/metainterp/warmstate.py b/rpython/jit/metainterp/warmstate.py --- a/rpython/jit/metainterp/warmstate.py +++ b/rpython/jit/metainterp/warmstate.py @@ -4,7 +4,7 @@ from rpython.jit.codewriter import support, heaptracker, longlong from rpython.jit.metainterp import history from rpython.rlib.debug import debug_start, debug_stop, debug_print -from rpython.rlib.debug import have_debug_prints +from rpython.rlib.debug import have_debug_prints_for from rpython.rlib.jit import PARAMETERS from rpython.rlib.nonconst import NonConstant from rpython.rlib.objectmodel import specialize, we_are_translated, r_dict @@ -639,7 +639,7 @@ 'disabled, no debug_print)' % drivername) # def get_location_str(greenkey): - if not have_debug_prints(): + if not have_debug_prints_for("jit-"): return missing greenargs = unwrap_greenkey(greenkey) fn = support.maybe_on_top_of_llinterp(rtyper, get_location_ptr) diff --git a/rpython/rlib/debug.py b/rpython/rlib/debug.py --- a/rpython/rlib/debug.py +++ b/rpython/rlib/debug.py @@ -141,10 +141,16 @@ # and False if they would not have any effect. return True +def have_debug_prints_for(category_prefix): + # returns True if debug prints are enabled for at least some + # category strings starting with "prefix" (must be a constant). + assert len(category_prefix) > 0 + return True + class Entry(ExtRegistryEntry): - _about_ = have_debug_prints + _about_ = have_debug_prints, have_debug_prints_for - def compute_result_annotation(self): + def compute_result_annotation(self, s_prefix=None): from rpython.annotator import model as annmodel t = self.bookkeeper.annotator.translator if t.config.translation.log: @@ -157,6 +163,12 @@ t = hop.rtyper.annotator.translator hop.exception_cannot_occur() if t.config.translation.log: + if hop.args_v: + [c_prefix] = hop.args_v + assert len(c_prefix.value) > 0 + args = [hop.inputconst(lltype.Void, c_prefix.value)] + return hop.genop('have_debug_prints_for', args, + resulttype=lltype.Bool) return hop.genop('have_debug_prints', [], resulttype=lltype.Bool) else: return hop.inputconst(lltype.Bool, False) diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py --- a/rpython/translator/c/funcgen.py +++ b/rpython/translator/c/funcgen.py @@ -796,6 +796,13 @@ def OP_DEBUG_STOP(self, op): return self._op_debug('PYPY_DEBUG_STOP', op.args[0]) + def OP_HAVE_DEBUG_PRINTS_FOR(self, op): + arg = op.args[0] + assert isinstance(arg, Constant) and isinstance(arg.value, str) + string_literal = c_string_constant(arg.value) + return '%s = pypy_have_debug_prints_for(%s);' % ( + self.expr(op.result), string_literal) + def OP_DEBUG_ASSERT(self, op): return 'RPyAssert(%s, %s);' % (self.expr(op.args[0]), c_string_constant(op.args[1].value)) diff --git a/rpython/translator/c/src/debug_print.c b/rpython/translator/c/src/debug_print.c --- a/rpython/translator/c/src/debug_print.c +++ b/rpython/translator/c/src/debug_print.c @@ -138,6 +138,7 @@ static unsigned char startswithoneof(const char *str, const char *substr) { + /* any([str.startswith(x) for x in substr.split(',')]) */ const char *p = str; for (; *substr; substr++) { @@ -154,6 +155,23 @@ return p != NULL; } +static long oneofstartswith(const char *str, const char *substr) +{ + /* any([x.startswith(substr) for x in str.split(',')]) */ + const char *p = substr; + for (; *str; str++) { + if (p) { + if (*p++ != *str) + p = NULL; /* mismatch */ + else if (*p == '\0') + return 1; /* full substring match */ + } + if (*str == ',') + p = substr; /* restart looking */ + } + return 0; +} + #if defined(_MSC_VER) || defined(__MINGW32__) #define PYPY_LONG_LONG_PRINTF_FORMAT "I64" #else @@ -199,3 +217,13 @@ display_startstop("", "}", category, debug_start_colors_2); pypy_have_debug_prints >>= 1; } + +long pypy_have_debug_prints_for(const char *category_prefix) +{ + pypy_debug_ensure_opened(); + return (!debug_profile && debug_prefix && + /* if 'PYPYLOG=abc,xyz:-' and prefix=="ab", then return 1 */ + (oneofstartswith(debug_prefix, category_prefix) || + /* if prefix=="abcdef" and 'PYPYLOG=abc,xyz:-' then return 1 */ + startswithoneof(category_prefix, debug_prefix))); +} diff --git a/rpython/translator/c/src/debug_print.h b/rpython/translator/c/src/debug_print.h --- a/rpython/translator/c/src/debug_print.h +++ b/rpython/translator/c/src/debug_print.h @@ -42,6 +42,7 @@ RPY_EXTERN void pypy_debug_stop(const char *category); RPY_EXTERN long pypy_debug_offset(void); RPY_EXTERN void pypy_debug_forked(long original_offset); +RPY_EXTERN long pypy_have_debug_prints_for(const char *category_prefix); RPY_EXTERN long pypy_have_debug_prints; RPY_EXPORTED FILE *pypy_debug_file; diff --git a/rpython/translator/c/test/red.ico b/rpython/translator/c/test/red.ico new file mode 100644 index 0000000000000000000000000000000000000000..6b93272462ebf1acbae64f6247ce64a68858f337 GIT binary patch [cut] diff --git a/rpython/translator/c/test/test_standalone.py b/rpython/translator/c/test/test_standalone.py --- a/rpython/translator/c/test/test_standalone.py +++ b/rpython/translator/c/test/test_standalone.py @@ -6,7 +6,8 @@ from rpython.rlib.objectmodel import keepalive_until_here from rpython.rlib.rarithmetic import r_longlong from rpython.rlib.debug import ll_assert, have_debug_prints, debug_flush -from rpython.rlib.debug import debug_print, debug_start, debug_stop, debug_offset +from rpython.rlib.debug import debug_print, debug_start, debug_stop +from rpython.rlib.debug import debug_offset, have_debug_prints_for from rpython.rlib.entrypoint import entrypoint, secondary_entrypoints from rpython.rtyper.lltypesystem import lltype from rpython.translator.translator import TranslationContext @@ -350,6 +351,8 @@ tell = -1 def entry_point(argv): x = "got:" + if have_debug_prints_for("my"): x += "M" + if have_debug_prints_for("myc"): x += "m" debug_start ("mycat") if have_debug_prints(): x += "b" debug_print ("foo", r_longlong(2), "bar", 3) @@ -387,7 +390,7 @@ assert 'bok' not in err # check with PYPYLOG=:- (means print to stderr) out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': ':-'}) - assert out.strip() == 'got:bcda.%d.' % tell + assert out.strip() == 'got:Mmbcda.%d.' % tell assert 'toplevel' in err assert '{mycat' in err assert 'mycat}' in err @@ -402,7 +405,7 @@ out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': ':%s' % path}) size = os.stat(str(path)).st_size - assert out.strip() == 'got:bcda.' + str(size) + '.' + assert out.strip() == 'got:Mmbcda.' + str(size) + '.' assert not err assert path.check(file=1) data = path.read() @@ -455,7 +458,7 @@ out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': 'myc:%s' % path}) size = os.stat(str(path)).st_size - assert out.strip() == 'got:bda.' + str(size) + '.' + assert out.strip() == 'got:Mmbda.' + str(size) + '.' assert not err assert path.check(file=1) data = path.read() @@ -486,7 +489,7 @@ out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': 'myc,cat2:%s' % path}) size = os.stat(str(path)).st_size - assert out.strip() == 'got:bcda.' + str(size) + '.' + assert out.strip() == 'got:Mmbcda.' + str(size) + '.' assert not err assert path.check(file=1) data = path.read() diff --git a/rpython/translator/platform/windows.py b/rpython/translator/platform/windows.py --- a/rpython/translator/platform/windows.py +++ b/rpython/translator/platform/windows.py @@ -417,6 +417,7 @@ deps = ['main.obj'] m.rule('wmain.c', '', ['echo #define WIN32_LEAN_AND_MEAN > $@', + 'echo #include "stdlib.h" >> $@', 'echo #include "windows.h" >> $@', 'echo int $(PYPY_MAIN_FUNCTION)(int, char*[]); >> $@', 'echo int WINAPI WinMain( >> $@', _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit